Asperger Asperger - 2 months ago 20
Java Question

Java alternative to @FXML injection of controllers?

So I have a master controller from the main fxml file and two other controllers from the includes files. Now I inject the child controllers via

@FXML ChildController childController
. Now it works and everyone who worked with FXML before knows what im talking about. The dependency injection with annotation is all fine but I want to do this myself because I have my own plans on handling all DIs.

(Question below)

This is how I initiate the entire thing:

public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Some resource"));

MainController mainController = new Controller();
loader.setController(mainController);

Scene scene = new Scene(loader.load(), w, h);

primaryStage.setScene(scene);

primaryStage.show();
}


Basically I want to do this:

SubController1 A = new SubController1();
SubController2 B = new SubController2();
MainController C = new MainControllerC(A, B);


So how can I do this with FXML (JavaFX)?

Answer

You can use a controller factory. If you set a controller factory on the FXMLLoader, the same controller factory will be used when any FXML files included by <fx:include> are loaded.

So:

Callback<Class<?>, Object> controllerFactory = new Callback<Class<?>, Object>() {

    SubController1 a = new SubController1();
    SubController2 b = new SubController2();
    MainController c = new MainController(a, b);

    @Override
    public Object call(Class<?> type) {
        if (type == SubController1.class) {
            return a ;
        }
        if (type == SubController2.class) {
            return b ;
        }
        if (type == MainController.class) {
            return c ;
        }
        return null ;
    }
};

And then

FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource(...));
loader.setControllerFactory(controllerFactory);
Parent root = loader.load();

The FXML files just declare the controller classes in the usual way, using fx:controller="...".

Controller factories can be pretty powerful: you can use a controller factory to allow a dependency injection framework (such as Spring or Guice) to manage the controllers for you (and inject dependencies into them), for example.