With a running JavaFX application, open a new window with its own, separate controller class

Kyte picture Kyte · Jan 20, 2014 · Viewed 16.1k times · Source

I'm using SceneBuilder in conjunction with Netbeans' JavaFX library for this project. I use Scenebuilder to create the fxml and netbeans for the controller classes. The goal is to build a fairly complex app that is to be deployed.

I can launch a JavaFX application and hook up the controller class just fine. However, when I try to open a new window I can't seem to bind a controller class to the new window. To keep things simple I would like to have a separate controller class for the new window due to a complex back-end.

TL;DR -- Trying to open a new window on JavaFX application with a controller class. Controller class isn't binding.

Code samples below

Model class -- wrapper for launching the application

public class Model extends Application{
    public static void main(String[] args){
         Application.launch(Model.class, args);
    }
    @Override
    public void start(Stage stage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }
}

Sample.fxml -- fxml file for the main application

Sample.java -- extends Initializable, is the controller class for Sample.fxml. Below is code snippet where I try to open the new window titled "ServerConfigChooser

try{
    Parent root = FXMLLoader.load(getClass().getResource("ServerConfigChooser.fxml"));
    FXMLLoader loader = new FXMLLoader(getClass().getResource("ServerConfigChooser.fxml"));
    ServerConfigChooser controller = new ServerConfigChooser();

    loader.setController(controller);
    loader.setRoot(root);

    Stage stage = new Stage();
    stage.setScene(new Scene(root));
    stage.show();
} catch (IOException ex)

ServerConfigChooser.java -- implements Initializable

This is where I have the problems. I cannot simply declare variables with the same fxid as the variables in the .fxml file. The initialize() method does not fire when the class is called.

The reason for the constructor in the ServerConfigChooser class is that I could not fire the initialize() method automatically. I fire that manually within the constructor.

Any solutions are welcome!

Answer

thomas.g picture thomas.g · Jan 20, 2014

Don't load the FXML twice like that. You can load multiple times the same .fxml document (multiple scene graph / controllers) but if you want to do together loading the scene graph and initializing the controller you have to call the fxml loader only once.

Here is an example

    FXMLLoader loader = new FXMLLoader(getClass().getResource("ServerConfigChooser.fxml"));
    ServerConfigChooser controller = new ServerConfigChooser();
    loader.setController(controller);
    loader.setRoot(controller);
    Parent root;
    try {
        root = (Parent) loader.load();
        Scene scene = new Scene(root, 320, 200);
        Stage stage = new Stage();
        stage.setScene(scene);
        stage.show();
    } catch (IOException ex) {
        Logger.getLogger(ServerConfigChooser.class.getName()).log(Level.SEVERE, null, ex);
    }

Note that

  • your controller should extend the node type of the root node of your .fxml document
  • your .fxml document should use fxroot construct, see this doc (you can set this in scene builder)
  • you should remove the controller from the fxml root element. It will conflict with this way of using the FXMLLoader class

For example the controller class

public class ServerConfigChooser extends AnchorPane implements Initializable {
   ...
}

And the .fxml

<fx:root type="javafx.scene.layout.AnchorPane" id="AnchorPane" prefHeight="200.0" prefWidth="320.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">