同步 textArea.clear() 后跟 textArea.setText() 不清除文本

Synchronous textArea.clear() followed by textArea.setText() does not clear text

单击按钮时,我想清除 textArea,做一些工作,然后在 textArea 中以相同的方法同步打印结果。

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

发生的情况是,textArea 已更新,但清除操作不可见。这项工作需要几秒钟。如果我注释掉除 textArea.clear() 之外的所有内容,它会起作用。

正如我在评论中提到的那样,JavaFX 直到 "pulse" 出现后才会渲染下一帧。当您清除文本,运行 一个 long-running 任务,然后在一个方法中全部设置文本时,不会发生这种情况;脉冲发生在所有这些发生之后,这意味着呈现的是新文本。此外,运行在 JavaFX 应用程序线程 上执行 several-seconds-long 任务也不是一个好主意。所有阻塞 and/or long-running 任务都应该在后台线程上完成——否则你的 GUI 会变得无响应(并且你的用户会变成 unhappy/nervous)。

如果此任务太简单而无法使用 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);

注意:这些示例将使用通用的 ForkJoinPool 执行 someSynchronousWork()。您可以通过将 Executor 传递给 supplyAsync.

来自定义它

注意:您可能希望在任务 运行 期间禁用某些 UI 组件(例如按钮)防止同时启动多个任务。任务完成后启用 UI 组件。


此外,您似乎在使用 ButtononMouseClicked 属性 来处理操作。考虑改用 onAction 属性; onAction 处理程序不仅会收到鼠标单击通知(例如,当按钮具有焦点并且 SpaceEnter被按下)。