私はJavaFX/Java 8アプリケーションをNetBeans 8で作成しました(SceneBuilder
なし)。
私のアプリケーションには、独自のFXMLファイル(primary.fxml)と独自のコントローラークラス(FXMLPrimaryController.Java)を持つメインウィンドウがあります。 FXMLの項目の1つはTextArea
です。 FXMLPrimaryController.Javaのメソッドのいくつかは、そのTextArea
に追加するものです。
このアプリケーションは、独自のFXML(second.fxml)と独自のコントローラークラス(FXMLsecondController.Java)を持つ2番目のウィンドウ(別の「ステージ」)を生成します。
2番目のコントローラークラス内で、プライマリのTextAreaにアクセスするにはどうすればよいですか?
関連するコードのサンプルを次に示します。
primary.fxml:
<Button text="press me!" onAction="#openSecondWindow" />
<TextArea fx:id="myArea" />
FXMLPrimaryController.Java:
public class FXMLPrimaryController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle rb) {
}
@FXML private TextArea myArea;
final public void writeToTextArea() {
myArea.appendText("hi!");
}
@FXML
private void openSecondWindow(ActionEvent event) throws Exception {
Group root = new Group();
Stage stage = new Stage();
AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
root.getChildren().add(frame);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
Second.fxmlに特別なことはありません。 onAction="#writeSomething"
。
FXMLsecondController.Javaでは、上記のTextArea
を参照する関数が必要です。
セカンダリコントローラのFXMLをロードするときは、次のようにします。
_FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("second.fxml"));
AnchorPane frame = fxmlLoader.load();
FXMLSecondaryController c = (FXMLSecondaryController) fxmlLoader.getController();
_
次に、2番目のコントローラーに参照を渡すことができます。これは単にTextAreaである可能性があります。
編集:
上記のスニペットのload()
呼び出しを置き換え、setLocation()
呼び出しを追加しました。古い行AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));
は、静的なload
関数を呼び出していたため間違っていましたが、ここでは役に立ちません。
編集:
(上記のコードスニペットを変数名とより一致するように変更しました。)上記のコードスニペットは、コードのこの部分を置き換えます。
_AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
_
この行はFXMLLoaderを使用してビューをロードし、コントローラーのインスタンス(この場合はFXMLSecondaryController
)も作成します。ただし、静的な_FXMLLoader.load
_メソッドを使用することはできません。FXMLLoader
のインスタンスが必要です。そのインスタンスは、ロード後にコントローラーへの参照を保持し、getController()
を使用してそれを取得できます。そして、戻り値をコントローラークラスにキャストする必要があります(_(FXMLSecondaryController)
_を使用)。
プライマリコントローラにはフィールドがあります:
_@FXML private TextArea myArea;
_
これはTextArea
への参照を保持し、fxmlローダーによって初期化されます。 (_@FXML
_アノテーションを削除すると、ローダーはそれに触れません。)
セカンダリコントローラで、次のフィールドを追加します。
_public TextArea primaryTextArea;
_
_@FXML
_がなくなっている(fxmlローダーはフィールドに触れない)ことに注意してください。また、private
(フィールドを設定する必要があるため、他のユーザーも参照する必要があります)。これで、コントローラがロードされた後にこのフィールドを設定できます。読み込みコードに戻ります。
_FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("second.fxml"));
AnchorPane frame = fxmlLoader.load();
FXMLSecondaryController c = (FXMLSecondaryController) fxmlLoader.getController();
// Add this too:
c.primaryTextArea = myArea;
_
編集:上記のスニペットのload()
呼び出しを置き換え、setLocation()
呼び出しを追加しました。古い行AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));
は、静的なload
関数を呼び出していたため間違っていましたが、ここでは役に立ちません。
FXMLSecondaryController
に、プライマリコントローラーのTextArea
への参照が追加されました。そのメソッドの1つで、そのコンテンツにアクセスできるはずです。
_public class FXMLSecondaryController implements Initializable {
// ...
public TextArea primaryTextArea;
// ...
@FXML
private void doSomething(ActionEvent event) throws Exception {
primaryTextArea.appendText("Hi ho!");
}
}
_
このソリューションは最善の方法ではありませんが、シンプルであり、最初に使用できることに注意してください。バインディングの使用は確かに推奨されます。データを保持し、他のコントローラーがバインドするクラスを作成しようとします。しかし、今のところ単純なアプローチをとれば、それで十分でしょう。
FXMLPrimaryControllerからTextFieldを公開し、FXMLsecondControllerにTextFieldプロパティを含めることができれば幸いです。次に、部品を組み立てるときにそのプロパティを設定します。ただし、コントローラーを介してビューの詳細を公開するため、これは良い設計とは言えません。
TextAreaは必要ないが、second.fxml
のTextAreaのデータは不要だと思います。したがって、各コントローラーでStringプロパティを公開し、それらをバインドすることをお勧めします。
public class FXMLPrimaryController {
private ReadOnlyStringWrapper text ;
@FXML
private TextArea myArea;
public void initialize() {
text= new ReadOnlyStringWrapper(this, "text");
text.bind(myArea.textProperty());
}
public ReadOnlyStringProperty textProperty() {
return text.getReadOnlyProperty();
}
public String getText() {
return text.get();
}
@FXML
private void openSecondWindow(ActionEvent event) throws Exception {
Group root = new Group();
Stage stage = new Stage();
AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
root.getChildren().add(frame);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
そして、FXMLsecondControllerで、
public class FXMLsecondController {
private StringProperty text ;
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println(text.getValue());
}
public void initialize() {
text = new SimpleStringProperty(this, "text");
}
public StringProperty textProperty() {
return text ;
}
public String getText() {
return text.get();
}
}
次に、このようなものを使用して、これら2つをバインドできます
FXMLLoader primaryLoader = new FXMLLoader(getClass().getResource("primary.fxml"));
Parent textAreaHolder = (Parent) primaryLoader.load();
FXMLLoader secondaryLoader = new FXMLLoader(getClass().getResource("second.fxml"));
Parent textAreaUser = (Parent) secondaryLoader.load();
FXMLPrimaryController primaryController = (FXMLPrimaryController) textAreaHolder.getController();
FXMLsecondController secondController = (FXMLsecondController) textAreaUser.getController();
secondController.textProperty().bind(primaryController.textProperty());
これにより、両方のコントローラーの変数text
がバインドされ、プライマリコントローラーのテキストエリアに入力された値をセカンダリコントローラーで簡単に使用できます。