Mark
Mark

Reputation: 11

Dynamically accessing/traversing/manipulating JavaFX nodes created from FXML outside the controller class

Could someone help me out. I'm new to JavaFX and FXML and I've tried for countless hours trying to do something without any luck. Could someone please show me a working example of code which

1) loads an FXML that contains nodes (such as labels and buttons) that are nested several layers deep within different panes and nodes;

2) traverse the entire scene listing the nodes (such as labels and buttons);

3) couple Java code to a node (such as the label and button) so that I can change its properties (such as it's label and contents) outside the controller class that is defined for the FXML.

My goal is to build the UI using the Scene Builder and then be able to dynamically change the contents of the scene as well as to add other nodes to it. My problem is I can't get to the objects within the scene/stage.

Here's the bit of the code that I've been working with. The comments suggest what I'm looking for.

//

public void start(Stage stage) throws Exception {
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Sample.fxml"));
    Parent root = (Parent)fxmlLoader.load();
    SampleController controller = (SampleController)fxmlLoader.getController();
    controller.label.setText("Label text has been set");
    controller.button.setText("Button text has been set");

    // Looking for an example of traversing all the objects within the controller
    // looking for an object such as a TableView and its columns. Would like to
    // attach code outside the controller which populates the TableView.

    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
}

Upvotes: 1

Views: 1589

Answers (1)

Ignatiamus
Ignatiamus

Reputation: 306

You have to get all the nodes within the root container recursively:

public void start(Stage stage) throws Exception {
   FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Sample.fxml"));
   Parent root = (Parent)fxmlLoader.load();

   List<Node> allNodes = getAllNodes(root);
   for(Node node : allNodes) {
      // do some stuff…
   }
   …
}

private List<Node> getAllNodes(Parent container) {
    List<Node> nodes = new ArrayList<Node>();
    for(Node node : container.getChildrenUnmodifiable())
    {
       nodes.add(node);
       if (node instanceof Parent) {
          Parent subContainer = (Parent) node;
          nodes.addAll( getAllNodes(subContainer) );
       }
    }
    return nodes;
}

You can access a @FXML-field (e.g. a TableView) of your controller just like you already did… :-)

Also, there's a method in TableView to get the columns, e.g. controller.tableView.getColumns()…

Just hold an instance of your controller globally to access it from everywhere.

Cheers

Upvotes: 0

Related Questions