JavaFx - Updating GUI

Solution 1:

If you run the entire process on the FX Application thread, then that is (effectively) the same thread that is being used to display the UI. If both the display of the UI, and your file iteration process are running in the same thread, only one can happen at once. So you prevent the UI from updating until the process is complete.

Here's a simple example where I just pause for 250 milliseconds between each iteration (simulating reading a reasonably large file). One button launches this in the FX Application thread (notice how the UI is unresponsive while this runs - you can't type in the text field). The other button uses a Task to run it in the background, properly scheduling updates to the UI on the FX Application thread.

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class UpdateTaskDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        Label label = new Label();
        Button runOnFXThreadButton = new Button("Update on FX Thread");
        Button runInTaskButton = new Button("Update in background Task");
        HBox buttons = new HBox(10, runOnFXThreadButton, runInTaskButton);
        buttons.setPadding(new Insets(10));
        VBox root = new VBox(10, label, buttons, new TextField());
        root.setPadding(new Insets(10));

        runOnFXThreadButton.setOnAction(event -> {
            for (int i=1; i<=10; i++) {
                label.setText("Count: "+i);
                try {
                    Thread.sleep(250);
                } catch (InterruptedException exc) {
                    throw new Error("Unexpected interruption");
                }
            }

        });

        runInTaskButton.setOnAction(event -> {
            Task<Void> task = new Task<Void>() {
                @Override 
                public Void call() throws Exception {
                    for (int i=1; i<=10; i++) {
                        updateMessage("Count: "+i);
                        Thread.sleep(250);
                    }
                    return null ;
                }
            };
            task.messageProperty().addListener((obs, oldMessage, newMessage) -> label.setText(newMessage));
            new Thread(task).start();
        });

        primaryStage.setScene(new Scene(root, 400, 225));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}