Javafx 在 SwingUtilities.invokeLater 中修改 "Label"
Javafx modifying "Label" in SwingUtilities.invokeLater
我想做以下事情:
- 单击一个按钮
- 将矩形涂成红色
- 等待 1 秒
- 将矩形涂成蓝色
在下面的代码中:
GraphicsContext gc;
Button myButton = new Button("Button!");
myButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gc.setFill(Color.RED);
gc.fillRect(0, 0, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
gc.setFill(Color.BLUE);
gc.fillRect(0, 0, 100, 100);
}
});
}
});
这很好用。它在 0,0 处创建了一个宽度和高度为 100 的红色框。但是当我尝试修改标签时,它崩溃了。
GraphicsContext gc;
Pane root = new Pane();
Button myButton = new Button("Button!");
Label myLabel = new Label("HELLO!"); // added
root.getChildren.add(myLabel);
myButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gc.setFill(Color.RED);
gc.fillRect(0, 0, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
gc.setFill(Color.BLUE);
gc.fillRect(0, 0, 100, 100);
myLabel.setText("WORLD!"); // modified here
}
});
}
});
我期待的结果是,
单击一个按钮
将矩形涂成红色
等待 1 秒
将矩形涂成蓝色
然后将标签文本从 HELLO!走向世界!
但是我遇到了一个错误。为什么会这样?我不能修改 SwingUtilities 中的任何 Pane 元素吗?
任何建议都会有所帮助。
编辑
这是我按下按钮时出现的错误
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:229)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent.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(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler.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 Lego.run(Lego.java:63)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
这是因为任何 Java FX components
都必须由 JavaFX Application Thread
管理,因为它们不是线程安全的(这与任何 Swing components
的原因完全相同必须由 AWT event dispatching Thread
) 管理,因此您需要使用 Platform.runLater(runnable)
间接修改您的标签,如下所示:
和Java8
Platform.runLater(() -> myLabel.setText("WORLD!"));
使用以前的版本Java
Platform.runLater(new Runnable() {
public void run() {
myLabel.setText("WORLD!");
}
}
);
我们使用SwingUtilities.invokeLater(runnable)
让AWT event dispatching thread
执行一些代码,在未来某个未指定的时间修改Swing components
,这与Platform.runLater(runnable)
的想法相同在 Java FX components
.
的情况下
注意: 仅使用 Swing
组件或仅使用 Java FX
组件,避免混合使用 Swing
和 JavaFX
组件,除非您别无选择
永远不要暂停 JFXAT,不要在上面休眠,你会杀死响应,创建一个线程,在上面休眠,然后在其中使用 Platform.runLater 更新 UI.
updateLbl(){
new Thread(new Runnable(){
Thread.sleep();//sleep //try catch
Platform.runLater ... //inside update ui
}).start();
}
我想做以下事情:
- 单击一个按钮
- 将矩形涂成红色
- 等待 1 秒
- 将矩形涂成蓝色
在下面的代码中:
GraphicsContext gc;
Button myButton = new Button("Button!");
myButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gc.setFill(Color.RED);
gc.fillRect(0, 0, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
gc.setFill(Color.BLUE);
gc.fillRect(0, 0, 100, 100);
}
});
}
});
这很好用。它在 0,0 处创建了一个宽度和高度为 100 的红色框。但是当我尝试修改标签时,它崩溃了。
GraphicsContext gc;
Pane root = new Pane();
Button myButton = new Button("Button!");
Label myLabel = new Label("HELLO!"); // added
root.getChildren.add(myLabel);
myButton.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gc.setFill(Color.RED);
gc.fillRect(0, 0, 100, 100);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
gc.setFill(Color.BLUE);
gc.fillRect(0, 0, 100, 100);
myLabel.setText("WORLD!"); // modified here
}
});
}
});
我期待的结果是,
单击一个按钮
将矩形涂成红色
等待 1 秒
将矩形涂成蓝色
然后将标签文本从 HELLO!走向世界!
但是我遇到了一个错误。为什么会这样?我不能修改 SwingUtilities 中的任何 Pane 元素吗?
任何建议都会有所帮助。
编辑
这是我按下按钮时出现的错误
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:229)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent.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(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler.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 Lego.run(Lego.java:63)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
这是因为任何 Java FX components
都必须由 JavaFX Application Thread
管理,因为它们不是线程安全的(这与任何 Swing components
的原因完全相同必须由 AWT event dispatching Thread
) 管理,因此您需要使用 Platform.runLater(runnable)
间接修改您的标签,如下所示:
和Java8
Platform.runLater(() -> myLabel.setText("WORLD!"));
使用以前的版本Java
Platform.runLater(new Runnable() {
public void run() {
myLabel.setText("WORLD!");
}
}
);
我们使用SwingUtilities.invokeLater(runnable)
让AWT event dispatching thread
执行一些代码,在未来某个未指定的时间修改Swing components
,这与Platform.runLater(runnable)
的想法相同在 Java FX components
.
注意: 仅使用 Swing
组件或仅使用 Java FX
组件,避免混合使用 Swing
和 JavaFX
组件,除非您别无选择
永远不要暂停 JFXAT,不要在上面休眠,你会杀死响应,创建一个线程,在上面休眠,然后在其中使用 Platform.runLater 更新 UI.
updateLbl(){
new Thread(new Runnable(){
Thread.sleep();//sleep //try catch
Platform.runLater ... //inside update ui
}).start();
}