Hen
Hen

Reputation: 653

Updating your UI and forcibly waiting before continuing JavaFX

I show here an image of my welcome scene.

image

The current behavior of the Create New Project button is shown here:

Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.hide();
Parent root = FXMLLoader.load(getClass().getResource("/view/scene/configure/NewProjectConfigureScene.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Configure New Project Settings");
stage.setScene(scene);
stage.show();

To explain it in words: the button is pressed -> I get the stage -> hide the current scene -> switch the stage to have a new scene -> re-display the stage. This behavior is working.

I am new to GUI programming so please bear with me as I explain what I need.

I am now trying to add a small feature where when the Create New Project button is pressed, a loading message appears in the current scene, I force the GUI to wait for a few seconds (so that the user has time to see this "loading" message) before continuing onto the next scene. The loading message would look something like this.

image

I really want to implement this feature because a loading message followed by a wait could be more intuitive and consequently improve my users experience when using the program.

My initial attempt was to do the following:

statusText.setText("Please wait..."); // statusText is the "loading message"
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
try {
    Thread.sleep(2000);                
} catch(InterruptedException ex) {
    Thread.currentThread().interrupt();
}
stage.hide();

Parent root = FXMLLoader.load(getClass().getResource("/view/scene/configure/NewProjectConfigureScene.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Configure New Project Settings");
stage.setScene(scene);
stage.show();

I just read here that you can never sleep the UI thread because it will freeze the entire application. So I've been trying the approach mentioned in the first answer from the above link, which says to use javafx.concurrent.Task, however I have been trying for a long time to no avail.

How do I update the UI, forcibly wait for a few seconds, and then display a new scene?

Upvotes: 6

Views: 7724

Answers (2)

jewelsea
jewelsea

Reputation: 159291

Instead of sleeping the thread, use a PauseTransition and load your new scene after the pause has finished.

createNewProject.setOnAction(event -> {
    statusText.setText("Please wait...");
    PauseTransition pause = new PauseTransition(
        Duration.seconds(1),
    );
    pause.setOnFinished(event -> {
        Parent root = FXMLLoader.load(
            getClass().getResource(
                "/view/scene/configure/NewProjectConfigureScene.fxml"
            )
        );
        Scene scene = new Scene(root);
        stage.setTitle("Configure New Project Settings");
        stage.setScene(scene);
        stage.sizeToScene();    
    });
    pause.play();
});

The above code assumes you have just a single stage, so you resize your "Welcome" stage to become the "Configure New Project Settings" stage.

Upvotes: 11

purring pigeon
purring pigeon

Reputation: 4209

You should try adding in ControlsFX this will help.

You can do the following:

   Service<T> service = new Service<T>(){
       @Override
       protected Task<T> createTask() {
       return new Task<T>() {
          @Override
          protected T call() throws Exception {
        //Do your processing here.                      }
          };
      }
    };
    service.setOnSucceeded(event -> {//do your processing});
    service.setOnFailed(event -> {//do your processing});              
    ProgressDialog pd = new ProgressDialog(service);
    pd.setContentText("Please wait while the window loads...");
    pd.initModality(Modality.WINDOW_MODAL);
    pd.initOwner(stage);
    service.start();

This will put your code on the background thread. ControlsFX dialogs start and stop with the service.

Upvotes: 0

Related Questions