我正在使用JavaFX逐步开发游戏,并且正在使用do while循环来等待用户输入。问题是,它是从fxml控制器的initialize方法调用的,这意味着该接口永远不会加载。解决方案是等待使用另一个线程,但是JavaFX不允许修改辅助线程中的任何节点。
我避免通过使用以下代码获得“不在FX应用程序线程上”:
public void initialize(URL arg0, ResourceBundle arg1) {
// I call the game engine to start the game sequence and I pass root into it for further use
engine = new GameEngine(root);
Platform.runLater(new Runnable() {
@Override
public void run() {
engine.start();
}
});
}
在engine.start()方法内部:
public void start() {
System.out.println("Game started");
text("Hello, stranger"); // a new Label inside VBox
do {
try {
Thread.sleep((long) 1000);
System.out.println("Sleeping...");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("Error... waiting?");
}
} while(this.listener == false); // Listener triggers when user inputs.
System.out.println("ENTER PRESSED, May proceed");
text("It worked!");
}
此外,GameEngine扩展了Thread,我不知道它如何影响多线程之外的任何事物。
启动代码后,UI崩溃,输出使Sleeping ...每秒都应有的跳动。
答案 0 :(得分:1)
您不能在JavaFX Application Thread上调用Thread.sleep()
和/或while
循环,因为这将导致GUI停止并等待循环结束。
解决方案是等待使用另一个线程,但是JavaFX不允许 从辅助线程修改任何节点。
是的,您不应该从非JavaFX Application Threads修改场景图,但这不会阻止您为进行实际修改的代码行调用Platform.runLater()
。您也可以使用Task来实现这一点。
很难提供任何具体的解决方案,因为我不知道listener
标志是如何更新的。
在fabian指出之前,我没有注意到start()
方法属于Thread
子类。您永远都不要覆盖Thread.start()
,并且更糟糕的是,不要在覆盖它时调用super.start()
。
因此,这里发生的是您的GameEngine
类不再像Thread
那样工作。调用engine.start()
只会在调用了线程engine.start()
的情况下执行您在覆盖中编写的任何代码(恰好是JavaFX Application Thread,因为您已将其包装在Platform.runLater()
中)。 / p>
如果您仍然希望扩展Thread
,则应移动代码以覆盖Thread.run()
。另外请注意,您应该删除Platform.runLater()
中的initialize()
,并将其放置在任何会影响GUI的代码中。
例如:
Platform.runLater(() -> {
myLabel.setText("User typed" + input);
});
答案 1 :(得分:0)
基本上,使用多线程必须是明智的。一个线程等待主线程编辑布局。放置
Platform.runLater(() -> {
// layout manipulations
});
围绕布局的操作可以在主线程之外按预期工作。