JavaFX UI зависает в потоке приложения JavaFX в приемнике событий, но работает с Platform.runLater - PullRequest
0 голосов
/ 07 ноября 2018

В моей программе JavaFX в настоящее время весь мой код выполняется в потоке приложений JavaFX (включая код игровой логики, который не обязательно обновляет интерфейс). Я читал, что вы должны запускать код не-пользовательского интерфейса в отдельном фоновом потоке, а затем обновлять его соответствующим образом в потоке приложений JavaFX, используя Platform.runLater или Tasks, чтобы пользовательский интерфейс не блокировался, но я все еще в замешательстве почему пользовательский интерфейс зависает, когда я просто вызываю myFlowPane.getChildren().remove() в потоке приложений JavaFX.

Надеемся, что следующий код обеспечивает достаточный контекст

hand.getTiles().addListener((ListChangeListener<ObservableTile>) change -> {
    while (change.next()) {
        if (change.wasAdded()) {
            for (Tile t : change.getAddedSubList()) {
                var btn = tileButtonFactory.newTileButton(t);
                fpHand.getChildren().add(change.getFrom(), btn);
            }
        } else if (change.wasRemoved()) {
            // Player can only remove 1 tile at a time
            Tile tile = change.getRemoved().get(0);
            fpHand.getChildren().removeIf(node -> ((TileButton)node).getTile().equals(tile));
        }
    }
});

У меня есть FlowPane, который содержит кучу кнопок, и я слушаю ObservableList, который содержит кучу плиток. Когда этот список плиток изменяется, я хочу соответствующим образом обновить FlowPane, чтобы при создании новых плиток я создал кнопку в FlowPane. Точно так же, когда плитка удаляется из этого списка плиток, я хочу, чтобы кнопка, содержащая эту плитку, была удалена из FlowPane.

Итак, из того, что я нашел в Интернете, слушатели событий запускаются в потоке приложений JavaFX. Это означает, что приведенный выше код выполняется в потоке приложения JavaFX. Когда я добавляю кнопку в FlowPane, пользовательский интерфейс не останавливается / блокируется fpHand.getChildren().add(). С другой стороны, когда я удаляю кнопку из FlowPane, пользовательский интерфейс зависает на fpHand.getChildren.remove.

Однако, когда я обертываю fpHand.getChildren.remove() вызов Platform.runLater(), пользовательский интерфейс отзывчив и не зависает. Почему это? Весь код в настоящее время выполняется в потоке приложений JavaFX.

Кроме того, у меня похожая проблема с другой частью моего кода. У меня есть GridPane с 128 ячейками (у каждой ячейки есть HBox), и мне нужно обновить таблицу. У меня есть следующий код:

private void updateTable() {
    Platform.runLater(() -> {
        clearTable();
        table.forEach(this::addTilesToTable);
    });
}
private void clearTable() {
    for (int row = 0; row < gpTable.getRowCount(); row++) {
        for (int col = 0; col < gpTable.getColumnCount(); col++) {
            getCellFromGridPane(row, col).ifPresent(hbox -> hbox.getChildren().clear());
        }
    }
}

Если я удаляю Platform.runLater(), пользовательский интерфейс не зависает полностью, но все плитки, которые я добавил ранее, сразу появляются, как будто на столе есть невидимая плитка, и поэтому я не могу добавить плитку там, хотя он должен быть пустым. Функция updateTable() также вызывается в потоке приложений JavaFX и в прослушивателе событий. Кажется, что hbox.getChildren.clear() не вызывается должным образом, если я удаляю Platform.runLater().

1 Ответ

0 голосов
/ 09 ноября 2018

Проблема, с которой я столкнулся, заключалась в том, что я использовал setMouseTransparent(true) для корневых панелей, которые содержат кнопки, содержащие плитку, для щелчка и перетаскивания, а не для использования событий мыши.

    node.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
        root.setMouseTransparent(true);
        dragContext.setMouseX(e.getSceneX());
        dragContext.setMouseY(e.getSceneY());
        dragContext.setInitialTranslateX(node.getTranslateX());
        dragContext.setInitialTranslateY(node.getTranslateY());
        e.consume();
    });

И когда вы отпустите кнопку мыши, она вернется к значению false

    node.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
        root.setMouseTransparent(false);
        node.setTranslateX(0);
        node.setTranslateY(0);
        e.consume();
    });

Проблема заключалась в том, что когда я удаляю кнопку со сцены, она уничтожает все обработчики событий, и, хотя я отпускаю мышь, он не запускает этот код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...