6

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?

Community
  • 1
  • 1
Hen
  • 633
  • 1
  • 9
  • 21

2 Answers2

11

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.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
0

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.

purring pigeon
  • 4,141
  • 5
  • 35
  • 68
  • Can you elaborate a bit for me? I don't think this does what I want.. which is to forcibly wait for a while after a loading message is displayed. – Hen Feb 12 '16 at 18:50
  • What this is doing is setting a MODAL window on top of your current stage so that user can't perform any other action. You would load the new view/stage/process in the call() method of the task. If you want fully modal and not just stage, set the initModality to Modality.APPLICATION_MODAL. If you do the logic on the main FX thread then the UI will block. Anything done in the call() method will happen on a background thread, and the UI is blocked because of the modal ProgressDialog. – purring pigeon Feb 12 '16 at 19:29