每个人都知道应该只允许JavaFX线程修改JavaFX应用程序中的GUI,但是很多时候我都在违反该规则的情况下出现怪异的行为,所以我编写了一个简单的程序:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
VBox root = new VBox();
CheckBox checkBox = new CheckBox("");
checkBox.setSelected(false);
root.getChildren().add(checkBox);
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
new Thread(()->{
System.out.println("is FX:"+Platform.isFxApplicationThread());
try {
//line under is 28
checkBox.selectedProperty().setValue(!checkBox.isSelected());
System.out.println("checkBox selectedProperty is change to:"+checkBox.isSelected()+","+ checkBox.selectedProperty().get());
}catch (Exception e){
System.out.println("checkBox change of selectedProperty is not allow from not FX thread");
}
try {
//line under is 35
checkBox.textProperty().set("test");
System.out.println("checkBox textProperty change to: "+checkBox.getText()+","+ checkBox.textProperty().get());
}catch (Exception e){
System.out.println("checkBox change of textProperty is not allow from not FX thread");
}
System.out.println("end of thread");
}).start();
}
public static void main(String[] args) {
launch(args);
}
}
输出:
is FX:false
checkBox selectedProperty is change to:true,true
checkBox textProperty change to: test,test
end of thread
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:247)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:493)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:271)
at javafx.controls/javafx.scene.control.skin.CheckBoxSkin.updateChildren(CheckBoxSkin.java:106)
at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.lambda$new$11(LabeledSkinBase.java:219)
at javafx.controls/com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler.lambda$new$1(LambdaMultiplePropertyChangeListenerHandler.java:49)
at javafx.base/javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at javafx.base/com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)
at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.base/javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:104)
at javafx.base/javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:111)
at javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:145)
at javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:50)
at sample.Main.lambda$start$0(Main.java:35)
at java.base/java.lang.Thread.run(Thread.java:844)
如您所见,GUI受以下两项更改影响:
但只有在第35行(textProperty
更改)而不是在28行(selectedProperty
更改)例外。
所以我的问题是一个错误,还是这种行为有一个合理的解释,如果存在,它是什么?
我不知道这是否重要,但是我使用Java 9
答案 0 :(得分:0)
这种现象是正常的。您从非GUI线程编辑GUI,从而使GUI处于不稳定状态。当GUI线程尝试刷新GUI时,会发生此异常。
答案 1 :(得分:0)
从另一个线程更改场景时,会发生以下情况之一:
只要您未将节点附加到场景,就不允许您从FX应用程序线程外部创建节点并对其进行修改。
将该节点放置到场景图时,则必须使用FX应用程序线程。