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?
