How do I access a UI element from another controller class in JavaFX?
fxml, java, java-8, javafx
Solution
When you load the FXML for the secondary controller, do this:
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("second.fxml"));
AnchorPane frame = fxmlLoader.load();
FXMLSecondaryController c = (FXMLSecondaryController) fxmlLoader.getController();
Then you can pass references to the second controller. This could just be the TextArea.
EDIT:
Replaced the `load()` call in the snippet above and added the `setLocation()` call. The old line `AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));` was wrong as it called the static `load` function, which is useless here.
EDIT:
(Changed the code snippet above to better match your variable names.) The code snippet above replaces this part of your code:
AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
That line uses the FXMLLoader to load the view and also creates the instance of the controller - in this case `FXMLSecondaryController`. However, you cannot use the static `FXMLLoader.load` method for that, you need an instance of `FXMLLoader`. That instance holds a reference to the controller after load and you can retrieve that with `getController()`. And you need to cast the returned value to your controller class (with `(FXMLSecondaryController)`).
Your primary controller has a field:
@FXML private TextArea myArea;
This holds a reference to your `TextArea` and is initialized by the fxml loader. (If you remove the `@FXML` annotation, the loader won't touch it.)
In your secondary controller, add this field:
public TextArea primaryTextArea;
Note that `@FXML` is gone (the fxml loader shall not touch the field) as well as `private` (you want to set the field, hence others must see it). Now you can set this field after the controller has been loaded. So back to the loading code:
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;
EDIT: Replaced the `load()` call in the snippet above and added the `setLocation()` call. The old line `AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));` was wrong as it called the static `load` function, which is useless here.
The `FXMLSecondaryController` now has a reference to the `TextArea` of the primary controller. In one of its methods you should be able to access its content:
public class FXMLSecondaryController implements Initializable {
// ...
public TextArea primaryTextArea;
// ...
@FXML
private void doSomething(ActionEvent event) throws Exception {
primaryTextArea.appendText("Hi ho!");
}
}
Note that this solution is not the best approach, but it is simple and can serve as a start. Using binding is certainly recommended. I would try to create a class which holds the data and on which the other controllers bind. But if you take the simple approach for now, it should be sufficient.
Problem
I have a JavaFX / Java 8 application written with NetBeans 8 (no `SceneBuilder`). My application has a main window that has its own FXML file (primary.fxml) and its own controller class (FXMLPrimaryController.java). One of the items in the FXML is a `TextArea`. Some of the methods in FXMLPrimaryController.java are about appending to that `TextArea`. This application now spawns a second window (another "stage") with its own FXML (second.fxml) and its own controller class (FXMLsecondController.java). Within the second controller class, how can I access the TextArea in the primary? Here's a sample of the relevant code: 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(); } } ``` There is nothing fancy about second.fxml. Assume there is a button with `onAction="#writeSomething"`. In FXMLsecondController.java, I would like a function that references the above `TextArea`.