Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javafx - load FXML file inside Controller, but also use NetBeans's "Make Controller"

While trying to load an FXML file, one usually does something like the following:

FXMLLoader loader = FXMLLoader.load(getClass().getResource("File.fxml"));
Region root = loader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();

However, as I tried to put the loading code into the controller for "caller convenience" I did the following:

public Controller()
{
   FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml));
   loader.setController(this);
   Parent root = loader.load();
   Stage stage = new Stage();
   stage.setScene(new Scene(root));
   stage.show();
}

This worked quite good, because now I just had to call the constructor to create the new window.

But I had to remove the

fx:controller="package.Class"

attribute in the FXML file, because otherwise an Exception ("javafx.fxml.LoadException: controller is already set") was thrown when I invoked the

fxmlloader.setController(this);

method in the constructor. Since I'm using NetBeans and its "Make Controller" feature (right-click on the FXML file), the controller class can't be created because of the missing attribute.

Summary:

What I want to achieve is a way to have the "fx:controller" attribute still set in the FXML (for NetBeans) and also being able to load the FXML conveniently inside the Controller class.

Is this possible, or do I need some kind of wrapper class which does create the FXML window(s)?

Thanks in advance.

like image 967
Ignatiamus Avatar asked Sep 15 '25 21:09

Ignatiamus


1 Answers

You can do this:

public Controller()
{
   FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml));
   loader.setControllerFactory(type -> {
       if (type == Controller.class) {
           return this ;
       } else {
           try {
               return type.newInstance();
           } catch (RuntimeException e) {
               throw e ;
           } catch (Exception e) {
               throw new RuntimeException(e);
           }
       }
   });
   Parent root = loader.load();
   Stage stage = new Stage();
   stage.setScene(new Scene(root));
   stage.show();
}

which will allow you to (in fact, you will need to) have the fx:controller attribute in the FXML file. Basically what this does is specifies a function that the FXMLLoader can use to get the controller instance from the specified class. In this case, if the FXML Loader is looking for an object of the Controller class, it returns the current object, otherwise just creates a new object of the specified class.

like image 96
James_D Avatar answered Sep 19 '25 16:09

James_D