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

我正在使用 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... 每一秒都应该如此。


天涯尽头无女友
浏览 153回答 2
2回答

慕容3067478

您不能在 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);     });

慕莱坞森

基本上,使用多线程必须是明智的。一个线程在主线程编辑布局时等待。推杆Platform.runLater(() -> {  // layout manipulations });如果在主线程之外,则围绕布局操作按预期工作。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java