JavaFX Preloader (Pantalla de Carga)

Un Preloader es una pantalla que se muestra antes de iniciar una aplicación JavaFX, mientras la misma está cargando, es recomendable utilizarla si nuestra aplicación tarda algo de tiempo al cargar, puesto que el usuario podría pensar que la aplicación no responde, por lo que mostrarle una pantalla indicándole que la aplicación está cargando y el progreso de la carga es una buena práctica de programación.

Netbeans 8.x Agregar Preloader


Abrimos Netbeans y creamos un nuevo proyecto tipo JavaFX Application.

javafx netbeans
Activamos la opción para crear un preloader, esto creará otro proyecto que contendrá el preloader, hacemos referencia a él desde el proyecto principal.

preloader netbeans javafx
Con esto el preloader ya es funcional, al ejecutar el proyecto principal veremos como aparece la pantalla de carga y se cierra inmediatamente, cuando la aplicación termina de cargar, puede ser que no se vea ya que el proyecto esta vacío y carga muy rápidamente, para simular una carga lenta haremos lo siguiente:

@Override
public void init() throws Exception {
        Thread.sleep(2500);
}

Al extender la case javafx.application.Application para crear una aplicación JavaFX podemos sobre escribir el método init(), este se ejecuta antes del método start(Stage), es ideal para tareas de inicialización, todo lo requerimos cargar antes de iniciar la aplicación podemos hacerlo aquí.

Para simular una carga que tarda 2.5 segundos agregaremos un retardo por la cantidad de tiempo mencionada, si ejecutamos el proyecto veremos la pantalla de carga durante 2.5 s.


Personalizar JavaFX Preloader


Para crear un preloader debemos extender la clase Preloader esta a su vez hereda de Application, por lo que crear una pantalla de carga es bastante similar a la creación de una aplicación JavaFX.

Vamos a modificar el preloader creado por netbeans, sobrescribimos el método start(Stage), aquí podemos crear el scene y agregarlo al stage correspondiente.

public class JFXTestPreloader_Preloader extends Preloader {

    private Stage stage;

    private Scene createPreloaderScene() {
        String url = getClass().getResource("loader.GIF").toExternalForm();
        ImageView progress = new ImageView(url);
        
        Label title = new Label("Tutor de Programación");
        title.setStyle("-fx-font-size: 2.3em; -fx-text-fill: whitesmoke;");
        
        Label footer = new Label("Blog: Tutor de Programación");
        footer.setStyle("-fx-font-size: 0.95em; -fx-text-fill: whitesmoke; -fx-font-style: oblique;");
        
        VBox root = new VBox();
        root.setSpacing(10.0);
        root.setAlignment(Pos.CENTER); 
        root.getChildren().addAll(title, progress);
        
        BorderPane pane = new BorderPane(root);
        pane.setBottom(footer);
        pane.setStyle("-fx-background-color: #2b579a;");
        
        return new Scene(pane, 480, 320, Color.TRANSPARENT);
    }

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        
        stage.initStyle(StageStyle.TRANSPARENT);
        stage.setScene(createPreloaderScene());
        stage.show();
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification scn) {
        if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
            stage.hide();
        }
    }

}

javafx preloader
El método handleStateChangeNotification(StateChangeNotification scn) maneja las notificaciones que llegan al preloader, por ejemplo la notificación de tipo StateChangeNotification.Type.BEFORE_START nos dice que la carga ha terminado, por lo podemos cerrar el stage.

Notificar Progreso al Preloader


En el primer ejemplo vemos cómo utilizar una pantalla de carga cuando no sabemos cuánto va tardar en cargar la aplicación, por ello utilizamos un preloader que solo muestra que la aplicación está cargando, en ocasiones podemos calcular el porcentaje de carga actual y mostrarlo en pantalla, veamos cómo hacerlo.

Usando los mismos proyectos, creamos una nueva aplicación JavaFX y otro preloader, debemos configurar netbeans para usar la nueva clase principal y el nuevo preloader.

cambiar main class y preloader java
Este preloader está construido con los gauges del proyecto Medusa, pueden cambiar por el diseño que más te guste o incluso crear personalizados.

@Override
public void handleApplicationNotification(PreloaderNotification pn) {
        if (pn instanceof ProgressNotification) {
            double value = ((ProgressNotification) pn).getProgress();
            gauge.setValue(value);
        } else if (pn instanceof StateChangeNotification) {
            stage.hide();
        }
}

Este preloader no estará controlado por el método init() de la aplicación principal, enviaremos una notificación de progreso cada vez que cambie el porcentaje de carga, al finalizar enviamos una notificación de cambio de estado, lo que cierra la pantalla de carga.

public class JFXTestMedusaPreloader extends Application {

    BooleanProperty ready = new SimpleBooleanProperty(false);

    private void longStart() {
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                int max = 100;
                // enviar notidicacion de progreso cada 50 ms
                for (int i = 1; i <= max; i++) {
                    Thread.sleep(50);
                    notifyPreloader(new ProgressNotification(i));
                }

                Thread.sleep(500);
                // indicar que la carga ha terminado, 100% completa
                ready.setValue(Boolean.TRUE);
                notifyPreloader(new StateChangeNotification(StateChangeNotification.Type.BEFORE_START));

                return null;
            }
        };
        new Thread(task).start();
    }

    @Override
    public void start(final Stage stage) throws Exception {
        // simular carga
        longStart();

        Label label = new Label("JavaFX Medusa Preloader");
        StackPane pane = new StackPane(label);
        stage.setTitle("Tutor de Programacion");
        stage.setScene(new Scene(pane, 400, 400));

        // Abrir el stage principal cuando la carga este al 100%
        ready.addListener((ov, t, t1) -> {
            if (Boolean.TRUE.equals(t1)) {
                Platform.runLater(() -> {
                    stage.show();
                });
            }
        });
    }

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

preloader javafx medusa
GitHub: JavaFX Pantalla de Carga
GitHub: Medusa Proyect

Comentarios

  1. Muy interesante y util, pero tengo una pregunta: ¿hay alguna forma de que la ventana de preloader se muestre en el paso de una ventana a otra?, es decir imagínate que después de cargar la ventana principal tengo un botón de abrir, que de de hay me cargue una nueva ventana, se puede hacer que en el paso de la ventana principal ha esta otra también aparesca la ventana de preloader

    ResponderEliminar
    Respuestas
    1. Claro que sí, puedes crear el preloader y asociarlo al stage principal de esta manera puedes ocultarlo y mostrarlo programaticamente, puedes ver este ejemplo: http://docs.oracle.com/javase/8/docs/technotes/guides/deploy/preloaders.html#BABBBBBJ

      Eliminar
    2. gracias, a probar se ha dicho :D

      Eliminar

Publicar un comentario

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Acceso a la webcam con OpenCV

JavaFx 8 Administrar ventanas

Analizador Léxico