Search code examples
javajavafxdelaypreloader

Delay between Preloader and Stage shown


I have a program that uses a simple preloader while the init() method creates the main gui. Everything works fine but after the init() method completes and the preloader disappears, there's a noticeable delay before the main stage shows up. I say noticeable because it can be as much as 7 seconds, enough for a user to get confused.

I tried to put as little as possible in the start() method:

public void start(Stage stage) {
    /*Scene*/
    scene = new Scene(root, 1200, 700);
    stage.setScene(scene);
    scene.setFill(null);

    /*Stage*/
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.centerOnScreen();
    stage.show();

}

Is there a way to reduce/eliminate this delay? Would it be better to scrap the preloader altogether and implement is as a stage in the main program? Thanks in advance.

EDIT:

I took Maverick283's advice and implemented a fadeOut of the preloader. There was still a bit of delay so I sent the final notification (from the main program to the preloader) after showing the main stage and it worked perfectly!

public void start(Stage stage) {
    /*Scene*/
    scene = new Scene(root, 1200, 700);
    stage.setScene(scene);
    scene.setFill(null);

    /*Stage*/
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.centerOnScreen();
    stage.show();
    notifyPreloader(new Preloader.ProgressNotification(0.99));
}

Solution

  • From Oracle:

    The last state change notification received by the preloader before the application starts is StateChangeNotification.Type.BEFORE_START. After it is processed, the application's start() method is called. However, it can take time before the application is ready to display its stage after the start() method is called. If the preloader stage is already hidden, then there could be a period of time when the application shows nothing on the screen.

    Thus they provide example code how to fix that:

    @Override
    public void handleStateChangeNotification(StateChangeNotification evt) {
        if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
            if (isEmbedded && stage.isShowing()) {
                //fade out, hide stage at the end of animation
                FadeTransition ft = new FadeTransition(
                    Duration.millis(1000), stage.getScene().getRoot());
                    ft.setFromValue(1.0);
                    ft.setToValue(0.0);
                    final Stage s = stage;
                    EventHandler<ActionEvent> eh = new EventHandler<ActionEvent>() {
                        public void handle(ActionEvent t) {
                            s.hide();
                        }
                    };
                    ft.setOnFinished(eh);
                    ft.play();
            } else {
                stage.hide();
            }
        }
    }
    

    If you continue reading there is even a way of sharing the two stages (preloader and main application stage)...