如何安全地从自己的线程修改JavaFX GUI节点?

6

我尝试在线程中更改JavaFX GUI节点,但是出现如下错误:

线程“Thread-8”中的异常java.lang.IllegalStateException:不在FX应用程序线程上; currentThread = Thread-8

生成错误的示例代码:

public class Controller { 
  public Label label = new Label();

  public void load() {
    MyThread myThread = new MyThread();
    myThread.start();
  }

  public class MyThread extends Thread {
    public void run() {
      ......
      label.setText(""); // IllegalStateException: Not on FX application thread
    }
  }
}

1
你的问题是什么? - David Schwartz
如何更改GUI元素? - user2954895
正如异常所示,您需要请求FX应用程序线程进行更改。 - David Schwartz
可以给个小例子吗?我正在主流中编写进度指示器。 - user2954895
1个回答

11

在活动场景图中对JavaFX节点进行的所有操作都必须在JavaFX应用程序线程上运行,否则您的程序可能无法正常工作。

当您尝试在JavaFX应用程序线程之外修改场景图节点的属性时,JavaFX将抛出异常IllegalStateException:Not on FX application thread。即使您没有收到IllegalStateException,也不应该在JavaFX应用程序线程之外修改场景图节点,因为如果这样做,您的代码可能会失败不可预测。

使用Platform.runLater()

将操作场景图节点的代码包装在Platform.runLater调用中,以允许JavaFX系统在JavaFX应用程序线程上运行代码。

例如,您可以使用以下代码修复示例程序:

Platform.runLater(() -> label.setText(""));

使用带有message属性的Task的替代方法

如果您正在使用JavaFX Task,它具有一些内置支持使用JavaFX进行并发编程的功能,则可以利用其message属性,该属性可以安全地从任何线程更新,但仅在JavaFX线程上中继属性更改。

这是一个示例(来自Task javadoc):

Task<Integer> task = new Task<Integer>() {
    @Override protected Integer call() throws Exception {
        int iterations;
        for (iterations = 0; iterations < 10000000; iterations++) {
            if (isCancelled()) {
                updateMessage("Cancelled");
                break;
            }
            updateMessage("Iteration " + iterations);
            updateProgress(iterations, 10000000);
        }
        return iterations;
    }
}; 

你可以安全地绑定到消息属性,以便在UI中反映出更改的消息值:
Label iterationLabel = new Label();
iterationLabel.textProperty().bind(
    task.messageProperty()
);

updateMessage javadoc:

更新消息属性。对于updateMessage的调用会被合并,稍后在FX应用程序线程上运行,因此即使从FX应用程序线程调用updateMessage,也可能不会立即更新此属性,并且中间的消息值可以合并以节省事件通知。

该方法可以安全地从任何线程调用。

Task javadoc中有许多使用updateMessage()的示例。


2
如果您正在使用 Java 8 或更高版本,则可以使其更短: Platform.runLater(() - > label.setText("")); - CodeBuddy
根据评论中的建议,更新示例以使用更现代的lambda形式。 - jewelsea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接