1

I am using JavaFX to show a view from my game.

The View is loaded when I call the method in my MainApp class:

public class MainApp extends Application {

    //fields

    public MainApp() {
        this.game = new Game();
    }

    //lots of other methods

    public void showGameView() {
        try {
            System.out.println(game.getPlayer().getCurrentRoom());
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("view/GameView.fxml"));
            AnchorPane GameView = (AnchorPane) loader.load();
            rootLayout.setCenter(GameView);
            GameViewController controller = loader.getController();
            controller.setMainApp(this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Game getGame() {
        return game;
    }

The Game object stores some information and stuff. The controller looks the following:

public class GameViewController {

    private MainApp mainApp;

    @FXML
    public void initialize() {
        mainApp.getGame().  ... //do something else
    }

    public void setMainApp(MainApp mainApp) {
        this.mainApp = mainApp;
    }

I have always done it that way. When the controller gets loaded, the MainApp objects gets set in the controller and I can work with that. But now I get a Nullpointer when any mainApp.get... gets called. The field mainApp is null. I dont really know what the deal is here, because as I said it worked like this in other projects.

2 Answers 2

2

The initialize method of the controller class is invoked at the end of the FXMLLoader.load method invocation, i.e. before you do

controller.setMainApp(this);

which means at this time the mainApp field still contains null.

You have to move the code dereferencing mainApp from the initialize method to the setMainApp method, create the controller instance with initialized mainApp property yourself and pass it to the FXMLLoader before loading (requires removal of fx:controller attribute) or using a controller factory to initialize the controller instance (which is probably the most complicated of the options).

Sign up to request clarification or add additional context in comments.

2 Comments

Ok so the field is empty because the field gets set after the initialize() gets called. I guess just calling another init() method in the setMainApp() is some kind of unclean but I guess I have to take it that way. Thank you
@Master1114 The usual approach would be to call mainApp.getGame(...) etc from the setMainApp(...) method; but if you want an additional init() method there is nothing to stop you doing that.
1

Really just an extension to fabian's answer. I agree that you should create the controller instance yourself (remove the fx:controller in the FXML as he said). It allows you to declare stuff as final which you otherwise wouldn't be able to, and avoids you having to have loads of setters in your public API which you otherwise wouldn't need.

You could probably move a lot of your initialise code into the constructor. I usually only put code in initialise if it directly modifies any of the JavaFX widgets.

It would look something like this:

public void showGameView() {
    try {
        System.out.println(game.getPlayer().getCurrentRoom());
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(MainApp.class.getResource("view/GameView.fxml"));
        loader.setController(new GameViewController(this));
        AnchorPane GameView = (AnchorPane) loader.load();
        rootLayout.setCenter(GameView);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

and

public class GameViewController {

    private final MainApp mainApp;

    public GameViewController(MainApp mainApp)
    {
        this.mainApp = mainApp;
    }

    @FXML
    public void initialize() {
        mainApp.getGame().  ... //do something else
    }

1 Comment

That looks like a pretty good and simple solution. And I guess its cleaner style than what I first thought in the comment on the other answers. Thank you aswell!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.