I want my application to update some elements but when I call Pane.getChildren().add() from another thread:
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();
I have this error:
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)
I tried to solve this according this Link but this approach do not helps: Platform.runLater(new Runnable(){});
Questions:
Why doesn't it work?
I want to my program to update itself UI in some delay, I think there is a right solution instead of mine)
Thanks in advance.
ADDITION for people who comment:
if I use Platform.runLater(new Runnable(){
It does not work different way. The program just froze and I understand why, but i do not understand why patch do not appear and don't change.
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();
}
}
}
});
If i use button It work well:
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);
}
});
ADDITION Here is "minimal reproducible example "that you can try.
press the button and there will be the result I need;
Delete comment " new Thread(new Runnable() {" and you will get "java.lang.IllegalStateException: Not on FX application thread"
Delete comment "Platform.runLater(new Runnable(){" and you get a frieze and motionless.
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);
}
}