我在 JavaFX 应用程序中遇到 java.lang.reflect.InvocationTargetException 异常,我不知道如何修复它

I'm getting an java.lang.reflect.InvocationTargetException exception in JavaFX app and I have no idea how to fix it

我正在构建一个小型 D&D 副项目,但在浏览 JavaFX 时遇到问题。我试图在同一个舞台上移动通过几个场景。我正在使用 MVC 设计并在调用控制器时通过 primaryStage。但是,当我尝试从我的 UI class 调用并从我的控制器获取舞台时,它会抛出 InvocationTargetException。

主要Class:

package dnd;

import javafx.application.Application;
import javafx.stage.Stage;

public class DnD extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception { 
        primaryStage.setTitle("Dungeons and Dragons");
        StartMenuCtrl startMenuCtrl = new StartMenuCtrl(primaryStage);
        primaryStage.show();        
    }

    public static void main(String[] args) {
        launch(args);
    }   
}

开始菜单控制器Class:

package dnd;

import javafx.stage.Stage;

public class StartMenuCtrl {
    private final StartMenuUI startMenuUI;
    private final Stage primaryStage;

    public StartMenuCtrl(Stage primaryStage) {
        this.startMenuUI = new StartMenuUI(this);
        this.primaryStage = new Stage();        
    }
    
    public void newButtonIsPressed() {
        System.out.println("New Button is pressed");
    }
    
    public void createButtonIsPressed() {
        System.out.println("Create Button is pressed");
        CreateCharCtrl createCharCtrl = new CreateCharCtrl(primaryStage);
    }
    
    public void loadButtonIsPressed() {
        System.out.println("Load Button is pressed");
    }
    
    public void joinButtonIsPressed() {
        System.out.println("Join Button is pressed");
    }
    
    public Stage getStage() {
        return this.primaryStage;
    }
}

开始菜单UIClass:

package dnd;

import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class StartMenuUI {
    private final StartMenuCtrl startMenuCtrl;
    private final Text title;
    private final Button newBtn;
    private final Button createBtn;
    private final Button loadBtn;
    private final Button joinBtn;

    public StartMenuUI(StartMenuCtrl startMenuCtrl) {
        this.startMenuCtrl = startMenuCtrl;
        this.title = new Text();
        this.newBtn = new Button("New Game");
        this.createBtn = new Button("Create Character");
        this.loadBtn = new Button("Load Saved Game");
        this.joinBtn = new Button("Join Game");
        initComponents();
    }
    
    private void initComponents() {
        Group root = new Group(title, newBtn, createBtn, loadBtn, joinBtn);
        Scene scene = new Scene(root, 1280, 720);
        Stage stage = startMenuCtrl.getStage();
        stage.setScene(scene);
    }
}

错误:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication4(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at dnd.StartMenuUI.initComponents(StartMenuUI.java:70)
    at dnd.StartMenuUI.<init>(StartMenuUI.java:25)
    at dnd.StartMenuCtrl.<init>(StartMenuCtrl.java:10)
    at dnd.DnD.start(DnD.java:11)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication11(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait4(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater3(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null7(WinApplication.java:177)
    ... 1 more

如有任何帮助,我们将不胜感激!我在这个项目中还很早,所以也将不胜感激 :)

您遇到了初始化顺序问题。在您的 StartMenuCtrl 构造函数中,您将对 this 的引用传递给 StartMenuUI 构造函数。 StartMenuUi 构造函数然后调用 initComponents,它调用 startMenuCtrl.getStage()... 但是那个方法 returns null 因为 StartMenuCtrl 构造函数还没有完成执行,并且还没有尚未初始化其 primaryStage 字段。

尝试重新排序 StartMenuCtrl 构造函数中的行,使它们按以下顺序排列:

this.primaryStage = new Stage(); // this needs to happen first!
this.startMenuUI = new StartMenuUI(this);

这个问题说明了为什么一般来说,it's best not to let the this reference escape during object construction