为了账号安全,请及时绑定邮箱和手机立即绑定

避免不在 FX 应用程序线程上导致 UI 崩溃

避免不在 FX 应用程序线程上导致 UI 崩溃

天涯尽头无女友 2021-11-24 15:30:23
我正在使用 JavaFX 制作一个循序渐进的游戏,我正在使用 do while 循环来等待用户输入。问题是,它是从 fxml 控制器初始化方法调用的,这意味着接口永远不会加载。解决方案是使用另一个线程等待,但 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... 每一秒都应该如此。
查看完整描述

2 回答

?
慕容3067478

TA贡献1773条经验 获得超3个赞

您不能在 JavaFX 应用程序线程上调用Thread.sleep()和/或while循环,因为这会导致 GUI 停止并等待循环结束。

解决方案是使用另一个线程等待,但 JavaFX 不允许从辅助线程修改任何节点。

是的,您不应该从非 JavaFX 应用程序线程修改场景图,但这并不能阻止您调用Platform.runLater()进行实际修改的代码行。您也可以使用Task来实现这一点。

很难提供任何具体的解决方案,因为我不知道listenerflag 是如何更新的。

编辑

直到 fabian 指出,我才注意到该start()方法属于一个Thread子类。你永远不应该覆盖Thread.start(),更糟糕的是,super.start()当你覆盖它时不要调用。

所以这里发生的事情是你的GameEngine类不再像Thread. 调用engine.start()只是在调用的线程中执行您在覆盖中编写的任何代码engine.start()(恰好是 JavaFX 应用程序线程,因为您已将其包装在 a 中Platform.runLater())。

如果您仍然喜欢扩展Thread,那么您应该将代码移动到覆盖Thread.run()。另请注意,您应该删除Platform.runLater()in initialize(),并将其放在会影响 GUI 的任何代码中。

例如:

Platform.runLater(() -> {
    myLabel.setText("User typed" + input);
    });


查看完整回答
反对 回复 2021-11-24
?
慕莱坞森

TA贡献1810条经验 获得超4个赞

基本上,使用多线程必须是明智的。一个线程在主线程编辑布局时等待。推杆


Platform.runLater(() -> {

  // layout manipulations 

});

如果在主线程之外,则围绕布局操作按预期工作。


查看完整回答
反对 回复 2021-11-24
  • 2 回答
  • 0 关注
  • 152 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信