#java #javafx
#java #javafx
Вопрос:
Приложение реагирует на действия, которые происходят на геймпаде. При нажатии кнопки что-то происходит в пользовательском интерфейсе. Но я столкнулся с проблемой зависания приложения или «java.lang.Исключение IllegalStateException: не в потоке приложения FX».
Чтобы исправить это, я попробовал следующие подходы: Platform.runLater()
и Task
использование. Но это не помогло.
Вот код проблемы:
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
) — в пользовательском интерфейсе появляется изображение. Когда пользователь отпускает эту кнопку ( rnd.nextInt(30) == 7
) — изображение исчезает из пользовательского интерфейса.
В случае java.lang.IllegalStateException: Not on FX application thread
, если происходит выше. Если вы измените RunTask () на что-то вроде этого:
Platform.runLater(new Runnable() {
@Override
public void run() {
initStubGamepad();
}
});
Тогда приложение зависнет или даже основной пользовательский интерфейс вообще не появится, но активность геймпада продолжается.
Я хочу просто показывать / скрывать разные изображения при обнаружении какой-либо активности на геймпаде (кстати, нет способа отслеживать активность геймпада, кроме опроса геймпада в бесконечном цикле). Что я сделал не так
Ответ №1:
Объяснение
В первом сценарии, когда вы используете
Task task = new Task<Void>() {
@Override
protected Void call() throws Exception {
initStubGamepad();
return null;
}
}
Внутри initStubGamepad()
, который выполняется для задачи, вы пытаетесь обновить компоненты пользовательского интерфейса внутри pressBtn()
и releaseBtn()
методы, поэтому вы сталкиваетесь с
java.lang.IllegalStateException: Not on FX application thread
поскольку все обновления пользовательского интерфейса должны выполняться в потоке JavaFX
Во втором сценарии, когда вы используете
Platform.runLater(new Runnable() {
@Override
public void run() {
initStubGamepad();
}
});
пользовательский интерфейс не отображается, потому что у вас есть бесконечный цикл внутри initStubGamepad()
, который запускает поток приложения JavaFX в бесконечном цикле
Решение
К тому времени, когда вы достигнете здесь, вы, должно быть, уже нашли решение. В случае, если вы этого не сделали, попробуйте установить обновление компонентов Javafx в потоке пользовательского интерфейса. Итак, вместо вызова initStubGamepad()
внутри Platform.runLater
, попробуйте вызвать pressBtn()
и releaseBtn()
внутри него.
Попробуйте использовать
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;
}
}
Комментарии:
1. Спасибо, большое спасибо за объяснение. Я понял, что было не так в моем использовании
Platform.runLater()
иTask
использовании.