Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX FXML controller - constructor vs initialize method

Tags:

java

javafx

My Application class looks like this:

public class Test extends Application {

    private static Logger logger = LogManager.getRootLogger();

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

        String resourcePath = "/resources/fxml/MainView.fxml";
        URL location = getClass().getResource(resourcePath);
        FXMLLoader fxmlLoader = new FXMLLoader(location);

        Scene scene = new Scene(fxmlLoader.load(), 500, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

The FXMLLoader creates an instance of the corresponding controller (given in the FXML file via fx:controller) by invoking first the default constructor and then the initialize method:

public class MainViewController {

    public MainViewController() {
        System.out.println("first");
    }

    @FXML
    public void initialize() {
        System.out.println("second");
    }
}

The output is:

first
second

So, why does the initialize method exist? What is the difference between using a constructor or the initialize method to initialize the controller required things?

Thanks for your suggestions!

like image 723
mrbela Avatar asked Jan 14 '16 09:01

mrbela


People also ask

How do controllers work in JavaFX using fxml?

Specifying Controller Class in FXML Notice the fx:controller attribute in the root element (the VBox element). This attribute contains the name of the controller class. An instance of this class is created when the FXML file is loaded. For this to work, the controller class must have a no-argument constructor.

What does Initializable do in JavaFX?

Called to initialize a controller after its root element has been completely processed. Parameters: location - The location used to resolve relative paths for the root object, or null if the location is not known. resources - The resources used to localize the root object, or null if the root object was not localized.

Should be public or annotated with @fxml?

You don't actually need any @FXML annotations if your fields are public . Of course, you should never make these fields public anyway; you should make them private , in which case all the @FXML annotations are required. But with the code as it is, omitting the annotations will make no difference.


3 Answers

In a few words: The constructor is called first, then any @FXML annotated fields are populated, then initialize() is called.

This means the constructor does not have access to @FXML fields referring to components defined in the .fxml file, while initialize() does have access to them.

Quoting from the Introduction to FXML:

[...] the controller can define an initialize() method, which will be called once on an implementing controller when the contents of its associated document have been completely loaded [...] This allows the implementing class to perform any necessary post-processing on the content.

like image 138
Nikos Paraskevopoulos Avatar answered Oct 04 '22 23:10

Nikos Paraskevopoulos


The initialize method is called after all @FXML annotated members have been injected. Suppose you have a table view you want to populate with data:

class MyController { 
    @FXML
    TableView<MyModel> tableView; 

    public MyController() {
        tableView.getItems().addAll(getDataFromSource()); // results in NullPointerException, as tableView is null at this point. 
    }

    @FXML
    public void initialize() {
        tableView.getItems().addAll(getDataFromSource()); // Perfectly Ok here, as FXMLLoader already populated all @FXML annotated members. 
    }
}
like image 20
Itai Avatar answered Oct 05 '22 00:10

Itai


In Addition to the above answers, there probably should be noted that there is a legacy way to implement the initialization. There is an interface called Initializable from the fxml library.

import javafx.fxml.Initializable;

class MyController implements Initializable {
    @FXML private TableView<MyModel> tableView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        tableView.getItems().addAll(getDataFromSource());
    }
}

Parameters:

location - The location used to resolve relative paths for the root object, or null if the location is not known.
resources - The resources used to localize the root object, or null if the root object was not localized. 

And the note of the docs why the simple way of using @FXML public void initialize() works:

NOTE This interface has been superseded by automatic injection of location and resources properties into the controller. FXMLLoader will now automatically call any suitably annotated no-arg initialize() method defined by the controller. It is recommended that the injection approach be used whenever possible.

like image 25
gkhaos Avatar answered Oct 04 '22 23:10

gkhaos