0

I have 2 sets of FXML/Controller - 1st set is the main window - 2nd set is a window with options

Both work just fine when I call them from Main.java

My folder strcture is

src
|--- main
       |--- java
             |---- com
                     |--- main
                           |-  Main.java

                     |----controllers
                           |- MainWindowController.java
                           |- OptionsWindowController.java
        |---resources
                |- mainWindow.fxml
                |- optionsWindow.fxml

So in Main.java

 public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/mainWindow.fxml"));
        Parent root = loader.load();
        MainWindowController mwController = loader.getController();
        mwController.init(primaryStage);
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }

That parts works just fine, I call the MainWindow and it's ok. The same if I switch the names and call OptionsWindow from here (with it's controller).

So both work from Main.java.

I want the OptionsWindow to be called from the MainWindow, so in MainWindowController.java I have a method (called from a menu item):

public void loadOptionsWindow(){
    Stage modal = new Stage();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/optionsWindow.fxml"));
    OptionsWindowController opwCotroller = loader.getController();
    modal.initModality(Modality.APPLICATION_MODAL);
    Parent optionsRoot = null;
    try {
        optionsRoot = loader.load();
        Scene sceneOptions = new Scene(optionsRoot);
        modal.setScene(sceneOptions);
        opwCotroller.init(modal);
        modal.showAndWait();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

But I get the following error:

java.lang.NullPointerException
    at com.controllers.MainWindowController.loadOptionsWindow(MainWindowController.java:190)

I've checked and the FXML is being reached, I've printed the loader.getLocation() and it's what should be, but loader.getController() returns null.

I've tried to move the fxml to the same folder as the controller and call it with

FXMLLoader loader = new FXMLLoader(getClass().getResource("/optionsWindow.fxml"));

This doesn't work because of Location not found

FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/controllers/optionsWindow.fxml"));

This doesn't work either because location not found.

So... If I have the fxml in the resoruce folder and call it from Main any of those windows work, but when called from a class in a different folder they don't.

I would like to have the fxml in the same folder as the controllers to make SceneBuilder know about the methods and all that. I use Intellij and SceneBuilder doesn't seem to be aware of methods when the class file of the controller is outside the folder of the fxml.

Just in case the code in the fxml is:

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.controllers.OptionsWindowController">
   <children>
      <Label layoutX="300.0" layoutY="64.0" text="COSAS" />
      <Button fx:id="bAceptar" layoutX="388.0" layoutY="342.0" mnemonicParsing="false" text="Button" />
   </children>
</AnchorPane>

I'm lost with this, nothing seems to work and I just don't get it.

Caronte Hades
  • 213
  • 1
  • 2
  • 4

1 Answers1

0

Just in case anyone finds this useful.

When you use the loader the first time (in Main.java in my case) seems that the loader is already "loaded".

So when you call a new loader you need to "load" it first

As easy as switching

The code from:

public void loadOptionsWindow(){
    Stage modal = new Stage();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/optionsWindow.fxml"));
    OptionsWindowController opwCotroller = loader.getController();
    modal.initModality(Modality.APPLICATION_MODAL);
    Parent optionsRoot = null;
    try {
        optionsRoot = loader.load();
        Scene sceneOptions = new Scene(optionsRoot);
        modal.setScene(sceneOptions);
        opwCotroller.init(modal);
        modal.showAndWait();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

To:

public void loadOptionsWindow(){
    Stage modal = new Stage();
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/optionsWindow.fxml"));

//removed the loader 

    modal.initModality(Modality.APPLICATION_MODAL);
    Parent optionsRoot = null;
    try {
        optionsRoot = loader.load();

//reinserted the loader AFTER the loader.load()
   OptionsWindowController opwCotroller = loader.getController();

        Scene sceneOptions = new Scene(optionsRoot);
        modal.setScene(sceneOptions);
        opwCotroller.init(modal);
        modal.showAndWait();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

And now works like a charm

Thx to Patrik and his answer in a different post that, despite my search for a couple days, I didn't manage to find earlier (https://stackoverflow.com/a/23461254/5483745)

Community
  • 1
  • 1
Caronte Hades
  • 213
  • 1
  • 2
  • 4