Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFx - Updating GUI

Tags:

java

javafx

All I wanted is to update a label as my program is running. I am reading some files and I wanted it to display the name of the file is was reading.

However, it only displays the last file using the code below (basically GUI doesn't respond until the whole process is completed):

static Text m_status_update = new Text(); //I declared this outside the function so dont worry
m_status_update.setText("Currently reading " + file.getName());

I got around 4-5 files and I just want to display the name.

I saw a similar question Displaying changing values in JavaFx Label , the best answer recommended the following:

Label myLabel = new Label("Start"); //I declared this outside the function so dont worry
myLabel.textProperty().bind(valueProperty);

However the valueProperty is a StringProperty and I am stuck converting a string into a string property.

Also, I saw this Refresh label in JAVAFX , but the OP could update the label based on action. I really dont have any action going on?

like image 686
Indigo Avatar asked Oct 24 '14 19:10

Indigo


People also ask

Is JavaFX still being updated?

JavaFX 16 was released in March 2021. JavaFX 17 was released in September 2021. JavaFX 18 was released in March 2022. JavaFX 19 was released in September 2022.

Is JavaFX still maintained?

Originally developed by Oracle and made an official part of the JRE with Java 8, JavaFX was removed again with Java 11 and continued as the open source project OpenJFX - still mainly maintained by Oracle, but in cooperation with Gluon and other active participants.

What is JavaFX platform runLater?

Platform. runLater(r) is a static method in class Platform, from package javafx. application. The parameter is an object of type Runnable, the same interface that is used when creating threads.

Which is the future of JavaFX?

With JavaFX, you can build many types of applications. Typically, they are network-aware applications that are deployed across multiple platforms and display information in a high-performance modern user interface that features audio, video, graphics, and animation.


1 Answers

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);
    }
}
like image 138
James_D Avatar answered Oct 17 '22 06:10

James_D