I have a time-consuming method that has to run on action of a button, and while I have that method running, I want the UI to be still active (i.e. the user can still interact with it). I have tried several solutions. One is to just run the method:
Label label = new Label("current text");
Button button = new Button("Button text");
button.setOnAction(event -> label.setText(runConputation())); // takes a long time
But that will lock the UI while it's running.
Another solution was to use a separate thread:
Label label = new Label("current text");
Button button = new Button("Button text");
button.setOnAction(event -> {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
label.setText(runConputation()); // takes a long time
}
});
thread.start();
});
But this throws an IllegalStateException: not in javafx thread
or something similar.
I tried adding a Platform.runLater()
, as I read that will fix the Exception:
Label label = new Label("current text");
Button button = new Button("Button text");
button.setOnAction(event -> {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
label.setText(runConputation()); // takes a long time
}
});
}
});
thread.start();
});
...but it locks the UI. It also looks ugly.
I tried to use Task
as well:
Label label = new Label("current text");
Button button = new Button("Button text");
button.setOnAction(event -> {
Thread thread = new Thread(new Task<Void>() {
@Override
public Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
label.setText(runConputation()); // takes a long time
}
});
return null;
}
});
thread.start();
});
With similar results.
I wanted to do something like:
Label label = new Label("current text");
Button button = new Button("Button text");
button.setOnAction(event -> {
Task<String> task = new Task<String>() {
@Override
public String call() throws Exception {
return runConputation();
}
};
Thread thread = new Thread(task);
thread.start();
// wait until thread is done
label.setText(task.getValue());
});
Is there a way to do this?