Javafx - Can application class be the controller class
Solution 1:
The default behavior of the FXMLLoader
is to create a new instance of the controller class and use that instance as the controller.
Specifically, the FXMLLoader
does something like:
- Read the root FXML element.
- If the root FXML element has a
fx:controller
attribute, then- If a controller already exists, throw an exception, otherwise create an instance of the specified class1 and set that as the controller
- If the root FXML element has a
- Continue parsing the FXML file. If elements have a
fx:id
attribute, and a controller exists (by any mechanism), inject those fields into the controller. Similarly register event handlers as calls to methods in the controller instance. - Invoke
initialize()
on the controller, if a controller exists and it has such a method.
So, the question you asked:
Can application class be the controller class
Yes, but it's probably a terrible idea. If you simply specify the Application
subclass as the controller class using fx:controller
, then a second instance of the Application
subclass is created, @FXML
-annotated fields are injected on that second instance, and the initialize()
method is invoked on that second instance. Obviously, the @FXML
-fields are never initialized on the instance on which start(...)
is invoked, and the initialize()
method is never invoked on that instance.
The question you probably meant is:
Can the application class instance created at launch be used as the controller?
The answer to this is also yes, and, aside from very small demo programs you intend to immediately discard, it's also probably a very bad idea. You would do this by
public class MyApp extends Application {
@FXML
private Node someNode ;
public void initialize() {
// do something with someNode
}
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
loader.setController(this);
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Note that to use this code, your FXML file must not have a fx:controller
attribute.
The problem with this is that you have no separation and no flexibility. (E.g. if you create a second instance of the view defined in your FXML file somewhere, you end up with a second Application
subclass instance, which is at best counterintuitive (one application with two Application
instances...).)
So I would advocate using a separate class for the controller in basically every case. The Application
subclass should contain minimal code and should be used only for starting the application.
1 This step is actually a little more complex. If a class is specified in the fx:controller
attribute, and no controller already exists, the FXMLLoader
checks for a controllerFactory
. If one exists, then the controller is set as the result of passing the specified Class
to the controllerFactory
's call()
method, otherwise it is created by calling newInstance()
on the specified class (effectively calling its no-argument constructor).
Solution 2:
If you have defined your application class to be the controller in the FXML file, JavaFX will, if I remember correctly, create a new instance of your application class and use the new instance as a controller. Thus, your existing application class still has null for the table.
You can however define the controller programmatically in your application class to use your own instance:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("example.fxml"));
fxmlLoader.setController(this);
Parent root = (Parent)fxmlLoader.load();