本文介绍了应用程序挂起或“不在FX应用程序线程上”在应用活动期间发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应用程序对游戏手柄上发生的操作做出反应。当按下按钮时,UI上会发生某些事情。但是我遇到了app挂起或java.lang.IllegalStateException:Not on FX application thread异常的问题。

The application reacts on actions which occur on gamepad. When button is pressed something happens on UI. But I ran at the issue with app hangs up or "java.lang.IllegalStateException: Not on FX application thread" exception.

为了解决这个问题我试过以下方法: Platform.runLater()任务用法。但它没有帮助。

In order to fix it I tried the following approaches: Platform.runLater() and Task usage. But it didn't help.

以下是问题代码:

public class GamepadUI extends Application{

    private static final int WIDTH = 300;
    private static final int HEIGHT = 213;

    private Pane root = new Pane();
    private ImageView iv1 = new ImageView();

    private boolean isXPressed = false;

    @Override
    public void start(Stage stage) throws Exception {
        initGUI(root);

        Scene scene = new Scene(root, WIDTH, HEIGHT);
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
    }

    public void pressBtn() {
        if(!isXPressed) {
            iv1.setVisible(true);
            isXPressed = true;
        }
    }

    public void releaseBtn() {
        if(isXPressed) {
            iv1.setVisible(false);
            isXPressed = false;
        }
    }

    private void initGUI(final Pane root) {
        Image image = new Image(Props.BUTTON);
        iv1.setImage(image);
        iv1.setLayoutX(198);
        iv1.setLayoutY(48);
        iv1.setVisible(false);
        root.getChildren().add(iv1);

        runTask();
    }

    public void runTask() {
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                initStubGamepad();
                return null;
            }
        };

        new Thread(task).start();
    }

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

    public void initStubGamepad() {
        Random rnd = new Random();
        try {
            while (true) {
                if (rnd.nextInt(30) == 3) {
                    pressBtn();
                } else if (rnd.nextInt(30) == 7) {
                    releaseBtn();
                }
            }
        } catch (Exception ex) {
            System.out.println("Exception: " + ex);
        }
    }
}

initStubGamepad()模拟游戏手柄按钮活动轮询。当用户按下任何按钮( rnd.nextInt(30)== 3 )时 - UI上会出现一个图像。当用户释放该按钮( rnd.nextInt(30)== 7 )时 - 图像从UI中消失。

initStubGamepad() emulates gamepad buttons activity polling. When user presses any button (rnd.nextInt(30) == 3) - an image appears on the UI. When user releases that button (rnd.nextInt(30) == 7) - an image disappears from the UI.

如果上面 java.lang.IllegalStateException:不在FX应用程序线程上发生。如果你将runTask()改为这样:

In case above java.lang.IllegalStateException: Not on FX application thread occurs. If you change runTask() to something like this:

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        initStubGamepad();
    }
});

然后应用程序将挂起,甚至主UI都不会出现,但游戏手柄活动会继续。

Then app will hang or even main UI won't appear at all, but gamepad activity continues.

我想要的只是在游戏手柄上检测到某些活动时显示/隐藏不同的图像(顺便说一句,除了无限循环中的游戏手柄轮询之外,没有办法监控游戏手柄活动)。我错了什么

What I want is just to show/hide different images when some activity is detected on gamepad (btw, there's no way to monitor gamepad activity except for gamepad polling in an infinite loop). What did I wrong

推荐答案

解释

第一种情况 中,当您使用时

In the first scenario, when you are using

Task task = new Task<Void>() {
  @Override
  protected Void call() throws Exception {
      initStubGamepad();
      return null;
  }
}

内部 initStubGamepad(),正在任务上运行,您正在尝试更新 pressBtn()和<$ c内的UI组件$ c> releaseBtn()方法,这就是为什么你要面对

Inside initStubGamepad(), which is running on a Task, you are trying to update the UI components inside pressBtn() and releaseBtn() methods, which is why you are facing a

java.lang.IllegalStateException: Not on FX application thread

因为所有UI更新必须在JavaFX线程上发生

第二种情况 中,当您使用时

In the second scenario, when you are using

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        initStubGamepad();
    }
});

用户界面没有出现,因为<无限循环 initStubGamepad(),它使JavaFX应用程序线程在无限循环上运行

the UI doesnt appear, because you have an infinite loop inside the initStubGamepad(), which puts the JavaFX application thread run on an infinite loop

解决方案

当你到达这里时,你必须已经找到了解决方案。如果还没有,请尝试将更新Javafx组件放在UI线程上。因此,不要在 Platform.runLater 中调用 initStubGamepad(),而是尝试调用 pressBtn() releaseBtn()在其中。

By the time you have reach here, you must have already found the solution. In case you haven't, try try to put the update the Javafx components on the UI thread. So, instead of calling initStubGamepad() inside Platform.runLater, try calling pressBtn() and releaseBtn() inside it.

尝试使用

while (true) {
   if (rnd.nextInt(30) == 3) {
      Platform.runLater(() -> pressBtn());
   } else if (rnd.nextInt(30) == 7) {
       Platform.runLater(() -> releaseBtn());
   }
}

或者您也可以使用

public void pressBtn() {
    if(!isXPressed) {
        Platform.runLater(() -> iv1.setVisible(true));
        isXPressed = true;
    }
}

这篇关于应用程序挂起或“不在FX应用程序线程上”在应用活动期间发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 15:27