英文:
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类调用并从控制器获取舞台时,它会抛出InvocationTargetException。
主类:
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);
}
}
开始菜单控制器类:
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 = primaryStage;
}
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;
}
}
开始菜单UI类:
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)
...
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
...
Caused by: java.lang.NullPointerException
at dnd.StartMenuUI.initComponents(StartMenuUI.java:70)
...
希望能对您有所帮助!由于项目刚刚开始,如果需要进行重大更改,也欢迎提出。
英文:
I'm building a small D&D side project, but having trouble navigating my way through JavaFX. I'm attempting to move through several scenes while remaining on the same stage. I'm using an MVC design and passing though the primaryStage whenever the controller is called. However, when I try to call from my UI class and get the stage from my controller, it throws a InvocationTargetException.
Main 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);
}
}
Start Menu Controller 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;
}
}
Start Menu UI Class:
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);
}
}
Error:
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$launchApplication$154(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$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(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$null$147(WinApplication.java:177)
... 1 more
Any help would be appreciated! I'm very early in the project so drastic change tips would be appreciated as well
答案1
得分: 5
你遇到了一个初始化顺序问题。在你的 StartMenuCtrl
构造函数中,你将对 this
的引用传递给了 StartMenuUI
构造函数。然后 StartMenuUi
构造函数调用 initComponents
,而 initComponents
又调用了 startMenuCtrl.getStage()
... 但是那个方法返回了 null
,因为 StartMenuCtrl
构造函数尚未执行完成,还没有初始化它的 primaryStage
字段。
尝试重新调整 StartMenuCtrl
构造函数中的行,使它们按照以下顺序排列:
this.primaryStage = new Stage(); // 这个需要首先发生!
this.startMenuUI = new StartMenuUI(this);
这个问题说明了为什么通常来说,在对象构造过程中最好不要让 this
引用逸出,具体可以参考这里的说明。
英文:
You've got an initialization order issue. In your StartMenuCtrl
constructor, you're passing a reference to this
to the StartMenuUI
constructor. The StartMenuUi
constructor then calls initComponents
, which calls startMenuCtrl.getStage()
... but that method returns null
because the StartMenuCtrl constructor has not finished executing, and has not yet initialized its primaryStage
field.
Try reordering the lines in the StartMenuCtrl constructor so they're in this order:
this.primaryStage = new Stage(); // this needs to happen first!
this.startMenuUI = new StartMenuUI(this);
This problem illustrates why, generally speaking, it's best not to let the this
reference escape during object construction.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论