关于JavaFX视图初始化的Nullpointer

时间:2016-12-05 16:36:47

标签: java javafx

我正在使用JavaFX来显示游戏中的视图。

当我在MainApp类中调用方法时加载视图:

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;
    }

Game对象存储一些信息和内容。控制器看起来如下:

public class GameViewController {

    private MainApp mainApp;

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

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

我一直这样做。当控制器加载时,MainApp对象在控制器中设置,我可以使用它。但是现在我在调用任何mainApp.get...时得到一个Nullpointer。字段mainApp为空。我真的不知道这里的交易是什么,因为我说它在其他项目中就像这样。

2 个答案:

答案 0 :(得分:2)

initialize方法调用结束时调用控制器类的FXMLLoader.load方法,即在执行之前

controller.setMainApp(this);

这意味着此时mainApp字段仍包含null

您必须将从mainApp方法解除引用initialize的代码移动到setMainApp方法,自己创建具有初始化mainApp属性的控制器实例并将其传递给加载前FXMLLoader(需要删除fx:controller属性)或使用控制器工厂初始化控制器实例(这可能是最复杂的选项)。

答案 1 :(得分:1)

真的只是法比安答案的延伸。我同意您应该自己创建控制器实例(如他所说,删除FXML中的fx:controller)。它允许您将内容声明为final,否则您将无法使用,并且避免您必须在公共API中加载大量的setter,否则您将不需要。

你可能会将很多initialise代码移到构造函数中。如果代码直接修改任何JavaFX小部件,我通常只将代码放在initialise中。

它看起来像这样:

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();
    }
}

public class GameViewController {

    private final MainApp mainApp;

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

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