javafx - 不在 FX 应用程序线程异常。当我尝试从 Thread 调用 Pane.getChildren().add()
问题描述
我希望我的应用程序更新一些元素,但是当我从另一个线程调用 Pane.getChildren().add() 时:
Pane root = new Pane();
Path path;
new Thread(new Runnable() {
@Override
public void run() {
for (Coordinate coordinate: coordinates){
try {
Thread.sleep(100);
root.getChildren().remove(path);
test++;
path = makePath(coordinates.subList(test, test+5));
root.getChildren().add(path);//!!!Exception here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
我有这个错误:
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:291)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:478)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at forTest.SkladPlanFx$2.run(SkladPlanFx.java:92)
at java.base/java.lang.Thread.run(Thread.java:844)
我试图根据这个链接解决这个问题, 但这种方法没有帮助:Platform.runLater(new Runnable(){});
问题:
为什么它不起作用?
我想让我的程序延迟更新自己的 UI,我认为有一个正确的解决方案而不是我的)
提前致谢。
添加评论的人:
如果我使用 Platform.runLater(new Runnable(){
它的工作方式不同。程序只是冻结了,我明白为什么,但我不明白为什么补丁不出现也不改变。
Platform.runLater(new Runnable(){
@Override
public void run() {
for (Coordinate coordinate: coordinates){
try {
Thread.sleep(100);
System.out.println(coordinate);
root.getChildren().remove(path);
test++;
path = makePath(coordinates.subList(test, test+5));
root.getChildren().add(path);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
如果我使用按钮效果很好:
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
root.getChildren().remove(path);
test++;
path = makePath(coordinates.subList(test, test+5));
Group group = new Group();
root.getChildren().add(path);
}
});
补充这是您可以尝试的“最小可重现示例”。
按下按钮,就会有我需要的结果;
删除注释“new Thread(new Runnable() {”你会得到“java.lang.IllegalStateException: Not on FX application thread”
删除评论“Platform.runLater(new Runnable(){”,你会得到一个楣板并且一动不动。
package forTest;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import java.util.Random;
public class SkladPlanFx extends Application {
static int test = 10;
Path path;
@Override
public void start(Stage primaryStage) {
// create a button with specified text
Button button = new Button("TEST");
button.setLayoutX(500);
button.setLayoutY(850);
Pane root = new Pane();
// create a scene specifying the root and the size
Scene scene = new Scene(root, 1320, 930);
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
root.getChildren().remove(path);
test++;
path = makePath();
Group group = new Group();
root.getChildren().add(path);
}
});
root.getChildren().add(button);
// add scene to the stage
primaryStage.setScene(scene);
// make the stage visible
primaryStage.show();
/*
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++){
try {
Thread.sleep(100);
root.getChildren().remove(path);
test++;
path = makePath();
root.getChildren().add(path);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
*/
/*
Platform.runLater(new Runnable(){
@Override
public void run() {
for (int i = 0; i < 20; i++){
try {
Thread.sleep(300);
System.out.println(i);
root.getChildren().remove(path);
test++;
path = makePath();
root.getChildren().add(path);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
*/
}
public Path makePath(){
Path path = new Path();
Random random = new Random();
path.getElements().add(new MoveTo(test++,test++));
for (int i = 0; i < 5; i++){
path.getElements().add(new LineTo(test++, test++));
}
return path;
}
public static void main(String[] args) {
Application.launch(SkladPlanFx.class, args);
}
}
解决方案
我已经通过这种方式解决了。
我在这个计时器内使用“new Timer().schedule()”而不是“Thread”加上 Platform.runLater()。
这样路径就可以改变了。
package Fx;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.util.*;
public class SkladPlanFx extends Application {
static int test = 0;
Path path;
public static void main(String[] args) {
SkladPlanFx.launch(SkladPlanFx.class, args);
}
@Override
public void start(Stage primaryStage) {
Text text = new Text();
text.setText("qqq");
text.setLayoutX(450);
text.setLayoutY(800);
Pane root = new Pane();
Scene scene = new Scene(root, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
//Timer
new Timer().schedule(
new TimerTask() {
@Override
public void run() {
System.out.println("ping " + ++test);
text.setText(" " + test);
//here is the solution
Platform.runLater(new Runnable() {
@Override public void run() {
root.getChildren().remove(path);
test++;
//path = makePath(coordinates.subList(test, test+5));
path = makeTestPath();
root.getChildren().add(path);
}
});
}
}, 0, 1000);
}
public Path makeTestPath() {
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(getRandomNumberInRange(1, 500), getRandomNumberInRange(1, 500)));
for (int i = 0; i < 10; i++) {
path.getElements().add(new LineTo(getRandomNumberInRange(1, 500), getRandomNumberInRange(1, 500)));
}
return path;
}
private static int getRandomNumberInRange(int min, int max) {
if (min >= max) {
throw new IllegalArgumentException("max must be greater than min");
}
Random r = new Random();
return r.nextInt((max - min) + 1) + min;
}
}
推荐阅读
- python-3.x - 如何根据其他单词的存在从字符串中提取某些单词?
- reactjs - 如何使胜利原生光标容器x和y轴线只与图形上的点相交而不与触摸点相交
- sql - LINQ to Entities 返回空列表,但它的 SQL 等效返回结果
- bash - 查找单行文件并将它们移动到子文件夹
- javascript - 内联事件处理程序中的作用域名称是如何创建的?这个机制在哪里记录?
- camel-http - Restlet 错误:“无法运行以下服务器端任务:sun.net.httpserver.ServerImpl$Exchange@56d26222”
- node.js - 如何在同一个 handler.js 文件中调用另一个 AWS 函数?并附加查询字符串参数?
- react-native - 如何添加填充或更改底部标签 RNN 的高度
- mysql - SQL query to get data between 2 date valid time table
- java - JavaFX 1.8 中的定时器(时钟)