I\'m currently teaching myself JavaFX, and I\'ve taken a simple example program that\'s hardcoded the view and am turning it into one that uses FXML (mostly so I can use Sce
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();
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:
fx:controller
attribute, then
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.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).