【发布时间】:2014-09-30 00:25:07
【问题描述】:
我正在尝试找到一种使用多线程来影响 JavaFX GUI 元素的形状和内容的有效方法,例如简单的Pane。假设我有一个简单的Pane,我在给定的时间间隔内显示填充Circles,我希望有机会回答它们,例如通过点击相应的键。到目前为止,为此目的,我尝试使用实现Runnable 接口并在其中创建经典Thread 对象的类,以便从外部JavaFX Pane 添加和/或删除元素,这是从主Application 类的构造函数参数中传递给该“线程类”。比如说,两个类,1) 应用程序和 2) 线程类,看起来像这样:
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ClassApplication extends Application {
private Pane pane;
public Parent createContent() {
/* layout */
BorderPane layout = new BorderPane();
/* layout -> center */
pane = new Pane();
pane.setMinWidth(250);
pane.setMaxWidth(250);
pane.setMinHeight(250);
pane.setMaxHeight(250);
pane.setStyle("-fx-background-color: #000000;");
/* layout -> center -> pane */
Circle circle = new Circle(125, 125, 10, Color.WHITE);
/* add items to the layout */
pane.getChildren().add(circle);
layout.setCenter(pane);
return layout;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(300);
stage.show();
/* initialize custom Thread */
ClassThread thread = new ClassThread(pane);
thread.execute();
}
public static void main(String args[]) {
launch(args);
}
}
...和“线程类”
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class ClassThread implements Runnable {
private Thread t;
private Pane pane;
ClassThread(Pane p) {
this.pane = p;
t = new Thread(this, "Painter");
}
@Override
public void run() {
try {
Thread.sleep(2000);
Circle circle = new Circle(50, 50, 10, Color.RED);
pane.getChildren().clear();
pane.getChildren().add(circle);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public void execute() {
t.start();
}
}
但是,这样的解决方案,在 Swing 应用程序中是可能的,在 JavaFX 中是不可能的,而且,是以下异常的原因:
Exception in thread "Painter" java.lang.IllegalStateException: Not on FX application thread; currentThread = Painter
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(Unknown Source)
at javafx.scene.Parent$2.onProposedChange(Unknown Source)
at com.sun.javafx.collections.VetoableListDecorator.clear(Unknown Source)
at ClassThread.run(ClassThread.java:21)
at java.lang.Thread.run(Unknown Source)
...“21”行是:pane.getChildren().clear();
我已经得出结论,“从另一个线程的级别影响主 JavaFX 线程存在问题”。但是在这种情况下,如果我不能(更准确地说是“我不知道如何”)绑定到几个线程,我该如何动态更改 JavaFX GUI 元素的形状和内容?
更新:2014/08/07,03:42
阅读给定答案后,我尝试在代码中实现给定解决方案,以便在不同位置显示 10 个自定义 Circles,每个显示之间具有指定的时间间隔:
/* in ClassApplication body */
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(300);
stage.show();
Timeline timeline = new Timeline();
for (int i = 0; i < 10; i++) {
Random r = new Random();
int random = r.nextInt(200) + 25;
KeyFrame f = new KeyFrame(Duration.millis((i + 1) * 1000),
new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent ae) {
pane.getChildren().add(new Circle(
random, random, 10, Color.RED));
}
});
timeline.getKeyFrames().add(f);
}
timeline.setCycleCount(1);
timeline.play();
}
上面的解决方案效果很好。非常感谢。
【问题讨论】:
标签: java multithreading javafx javafx-8