来自另一个线程的javafx绑定

时间:2015-08-27 16:57:56

标签: java multithreading binding javafx

所以我有一个Controller类,它包含 StringProperty ObservableList 。当我从另一个线程更改任何 StringProperty 对象时,它可以工作。但是,如果我尝试将此 StringProperty 对象绑定到Label,然后从不同的线程更改此对象,则会引发大量错误。 控制器类:

public class Controller implements Initializable{
protected static ObservableList<StringProperty><StringProperty> downloadingsPosition = nFXCollections.observableArrayList();
protected static ObservableList<StringProperty><StringProperty> downloadingsSize = FXCollections.observableArrayList();
private void saveActionEvent() {
...
 position.textProperty().bind(positionString);
 size.textProperty().bind(sizeString);
}
...
}

流程类:

public class Process implements Runnable {
private FileOutputStream fos;
private int number;
private double totalSize;

public Process(FileOutputStream fos, int number, double totalSize) {
    this.fos = fos;
    this.number = number;
    this.totalSize = totalSize;
}

public void run() {
    double size = 0;

    String totalSizeStr = String.valueOf("of " + Double.toString(totalSize / 1024.0));
    Controller.downloadingsSize.get(number).setValue(totalSizeStr);

    try {
        while (size < totalSize) {
            size = fos.getChannel().size() / (1024.0 * 1024.0);
            Controller.downloadingsPosition.get(number).setValue(Double.toString(size));
            TimeUnit.MILLISECONDS.sleep(500);
            System.out.println(size);
        }
    }
    catch (Exception e) {

    }

}

}

这些是错误:

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:204)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:438)
    at javafx.scene.Parent$2.onProposedChange(Parent.java:364)
    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$61(BehaviorSkinBase.java:197)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$96/698755630.call(Unknown Source)
    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.access$000(StringPropertyBase.java:49)
    at javafx.beans.property.StringPropertyBase$Listener.invalidated(StringPropertyBase.java:230)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    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 sample.Process.run(Process.java:30)
    at java.lang.Thread.run(Thread.java:745)

1 个答案:

答案 0 :(得分:0)

您需要阅读这篇文章:https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

总结的问题是JavaFX期望UI的任何更改都发生在运行应用程序的主线程上。如果您需要从另一个线程进行更改,您应该使用消息队列与主线程进行通信。

或者,如本文所述,您可以使用JavaFX提供的一种结构来跨线程进行更改。