Синхронный textArea.clear (), за которым следует textArea.setText (), не очищает текст - PullRequest
1 голос
/ 21 июня 2019

Когда нажимается кнопка, я хочу очистить textArea, выполнить некоторую работу, а затем распечатать результаты в textArea, все одним и тем же способом, синхронно.

public void resetClicked(MouseEvent mouseEvent) {
    textArea.clear();
    String result = someSynchronousWork();
    textArea.setText(result);
}

Что происходит, textArea обновляется, но действие очистки не отображается. Работа занимает несколько секунд. Если я закомментирую все, кроме textArea.clear(), это сработает.

1 Ответ

2 голосов
/ 21 июня 2019

Как я упоминаю в своем комментарии, JavaFX не рендерит следующий кадр, пока не произойдет "пульс" . Этого не произойдет, если вы очистите текст, запустите долгосрочную задачу, а затем установите текст в одном методе; импульс происходит после всего этого, что означает, что передается новый текст. Кроме того, выполнение задачи продолжительностью в несколько секунд в потоке приложений JavaFX не является хорошей идеей. Все блокирующие и / или длительные задачи должны выполняться в фоновом потоке - в противном случае ваш графический интерфейс перестает отвечать на запросы (а пользователи становятся несчастными / нервными).

Если эта задача слишком проста, чтобы использовать Task, тогда вы можете попробовать CompletableFuture, что может упростить вам вызов простых вещей в асинхронном режиме.

public void resetClicked(MouseEvent event) {
    event.consume();

    textArea.clear();
    CompletableFuture.supplyAsync(this::someSynchronousWork)
            .whenCompleteAsync((result, error) -> {
                if (error != null) {
                     // notify user
                } else {
                    textArea.setText(result);
                }
            }, Platform::runLater);
}

В зависимости от того, как вы хотите обрабатывать ошибки, вы можете делать разные вещи. Например:

// can't ever be an error
supplyAsync(this::someSynchronousWork)
        .thenAcceptAsync(textArea::setText, Platform::runLater);

// just want to show "Error" in text area on error
supplyAsync(this::someSynchronousWork)
        .exceptionally(error -> "ERROR")
        .thenAcceptAsync(textArea::setText, Platform::runLater);

Примечание: В этих примерах будет выполнено someSynchronousWork() с использованием общего ForkJoinPool. Вы можете настроить это, передав Executor в supplyAsync.

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


Кроме того, вы, похоже, используете onMouseClicked свойство Button для обработки действий. Попробуйте вместо этого использовать свойство onAction; обработчик onAction получает уведомление не только о щелчках мыши (например, когда кнопка имеет фокус и нажата Пробел или Ввод ).

...