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!
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.
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.
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.
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.
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.
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With