Leonardo Leonardo - 2 months ago 38
Java Question

JavaFX - Wrapping FXML to Java Class Controller

I have a FXML file that has a TreeView control:

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0" xmlns:fx="http://javafx.com/fxml" fx:controller="test.MyControllerClass">

<TreeView fx:id="locationTreeView" layoutX="12.0" layoutY="158.0" prefHeight="193.0" prefWidth="471.0" />


Then my Java Class Controller needs to wrap with this TreeView and add TreeItem's dynamically. That's the problem, it isn't loading those TreeItem's. That's the test code below, from my Controller:

public class MyControllerClass extends Application {

@FXML
private TreeView<String> locationTreeView;

@Override
public void start(Stage stage) throws Exception {

stage.initStyle(StageStyle.TRANSPARENT);
stage.getIcons().add(new Image(getClass().getResourceAsStream("myIcon.png")));

Parent root = FXMLLoader.load(getClass().getResource("myInterface.fxml"));

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

loadTreeItems();

stage.show();
}

// Just a simple example that still doesn't works
private void loadTreeItems() {

try {
TreeItem<String> root = new TreeItem<String>("Root Node");
root.setExpanded(true);
root.getChildren().addAll(
new TreeItem<String>("Item 1"),
new TreeItem<String>("Item 2"),
new TreeItem<String>("Item 3")
);

locationTreeView = new TreeView<String>(root);

} catch (Exception exc) {
System.out.println("Error: " + exc.getMessage());
}
}

public static void main(String[] args) {
launch(args);
}
}


Any ideas why its not working?

Answer

There are a couple of reasons why your application doesn't work:

  1. You need to make the Controller and the Application separate classes.
  2. You should allow the FXML system to inject the TreeView instance rather than creating a new instance (as Aaron points out in his answer).

The way you have your application currently structured what will happen is:

  1. The Java system will create an instance of MyControllerClass on startup (and invoke it's start method).
  2. The FXMLLoader will create another instance of MyControllerClass each time the myInterface.fxml file is loaded.
  3. The FXMLLoader will create a new TreeView instance and perform the FXML injection on the locationTreeView member of the new MyControllerClass instance it creates.
  4. The FXMLLoader will try to invoke the initialize method on the new MyControllerClass (of which you have none).
  5. The FXMLLoader will not invoke the start method on the new MyControllerClass.
  6. Your original start method invocation on your original MyControllerClass will continue processing and create another new TreeView instance which it will set the locationTreeView member of the old MyControllerClass instance to.

I updated your code to make the modifications I suggested above and the code now works. The updated code is available.

A sample screenshot from the running code is: dynamictreeview

Comments