不在FX应用程序线程上; currentThread =线程5

时间:2019-07-16 19:58:59

标签: multithreading javafx javafx-8

Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
    at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
    at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$70(BehaviorSkinBase.java:197)
    at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
    at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
    at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
    at javafx.scene.control.Labeled.setText(Labeled.java:145)
    at edu.controller.GUIController.statusShow(GUIController.java:443)
    at edu.controller.GUIController.lambda$7(GUIController.java:214)
    at java.lang.Thread.run(Unknown Source)

我正在做一个文本编辑器,我想在页脚中添加一个状态栏,该状态栏会在几秒钟后告诉用户不同的提示,当我尝试在标签上设置文本但当我遇到这种错误时,我会遇到此错误尝试在工作正常的控制台上设置该文本。

new Thread(()->{
    statusBarShow();
}).start();

private void statusBarShow(){
try {
    statusLable.setText("Tip 1");
    Thread.sleep(2000);
    statusLable.setText("Tip 2");
    Thread.sleep(2000);
    statusLable.setText("Tip 3");
    Thread.sleep(2000);
    statusLable.setText("Tip 4");
    Thread.sleep(2000);
    statusLable.setText("Tip 5");
    Thread.sleep(2000);
} catch (Exception e) {
    e.printStackTrace();
}
}

1 个答案:

答案 0 :(得分:2)

唯一允许修改JavaFX GUI的线程是JavaFX线程。如果任何其他线程修改了UI,您将获得异常。

此常见问题的最简单答案是将更改GUI的代码包装在Platform.runLater()中。注意不要在runlater()中放置任何睡眠,因为它们会导致JavaFX GUI线程睡眠,这将导致您的程序在睡眠期间冻结。

Platform.runLater()具有以下javadoc:

  

在某些情况下在JavaFX Application Thread上运行指定的Runnable   未来未指定的时间。此方法可以从   任何线程,都会将Runnable发布到事件队列,然后返回   立即给呼叫者。 Runnables按顺序执行   他们被张贴。传递给runLater方法的runnable将是   在任何Runnable传递给后续调用之前执行   runLater。如果已在JavaFX运行时之后调用此方法   关闭时,调用将被忽略:Runnable将不会执行   不会抛出异常。

     

注意:应用程序应避免将太多未决的JavaFX淹没   Runnables。否则,应用程序可能无法响应。   鼓励应用程序将多个操作分批处理   runLater调用。此外,应执行长时间运行的操作   在可能的情况下在后台线程上释放JavaFX   GUI操作的应用程序线程。

     

不得在FX运行时之前调用此方法   初始化。对于扩展应用程序的标准JavaFX应用程序,   并使用Java启动器或其中的一种启动方法   应用程序类来启动应用程序,FX运行时是   在加载Application类之前由启动程序初始化。   对于使用JFXPanel显示FX内容的Swing应用程序,FX   当第一个JFXPanel实例为   建造。对于使用FXCanvas显示FX的SWT应用程序   内容,在第一个FXCanvas初始化FX运行时   实例已构建。

我认为您的代码不是以最佳方式完成此任务的,但以下是一个非常简单的解决方案:

new Thread(()->{
    statusBarShow();
}).start();

private void statusBarShow(){
    try {
        Platform.runLater(()->statusLable.setText("Tip 1"));
        Thread.sleep(2000);
        Platform.runLater(statusLable.setText("Tip 2"));
        Thread.sleep(2000);
        Platform.runLater(statusLable.setText("Tip 3"));
        Thread.sleep(2000);
        Platform.runLater(statusLable.setText("Tip 4"));
        Thread.sleep(2000);
        Platform.runLater(statusLable.setText("Tip 5"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

一个更好的解决方案是使用AnimationTimer

以下是有关如何完成此操作的有用线程:JavaFX periodic background task