Javafx progress indicator in interface construction

Asked

Viewed 206 times

1

I need to create a progress indicator so that the user has a sense that the program is running something from behind.

Briefly I want to upload images to a TilePane grid gallery style, however when I try to upload these images it can sometimes take what makes the program appear to be stuck.

The gallery is based on this link: https://stackoverflow.com/a/27184788/3792998

inserir a descrição da imagem aqui

Code:

import Controller.FxmlSplashLoadingController;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.TilePane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class TestExample extends Application {

    Stage stage;
    TilePane tile;
    @Override
    public void start(Stage primaryStage) throws Exception {
        stage = primaryStage;
        ScrollPane root = new ScrollPane();
        tile = new TilePane();
        root.setStyle("-fx-background-color: DAE6F3;");
        tile.setPadding(new Insets(15, 15, 15, 15));
        tile.setHgap(15);

        //loading example
        Stage stageLoader = createLoaderSplashBar();
        //stageLoader.show();
        stageLoader.setAlwaysOnTop(true);
        // here runs the JavaFX thread
        // Boolean as generic parameter since you want to return it

        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        taskLongLoadImg();

                    }
                });

                return null;
            }
        };

        task.setOnRunning((e) -> stageLoader.show());
        task.setOnSucceeded((e) -> {
            stageLoader.hide();
            //Boolean returnValue = task.get();
            // process return value again in JavaFX thread
        });
        task.setOnFailed((e) -> {
            // eventual error handling by catching exceptions from task.get()  
        });
        new Thread(task).start();

        root.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); // Horizontal
        root.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); // Vertical scroll bar
        root.setFitToWidth(true);
        root.setContent(tile);

        primaryStage.setWidth(Screen.getPrimary().getVisualBounds().getWidth());
        primaryStage.setHeight(Screen.getPrimary().getVisualBounds()
                .getHeight());
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public Stage createLoaderSplashBar() {

        Stage newStage = new Stage();
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/View/FxmlSplashLoading.fxml"));
        Parent root = null;
        try {
            root = (Parent) fxmlLoader.load();
        } catch (IOException ex) {
            System.out.println("Error  -  Loading FxmlSplashLoading.fxml");
            Logger.getLogger(TestExample.class.getName()).log(Level.SEVERE, null, ex);
        }
        FxmlSplashLoadingController controller = fxmlLoader.<FxmlSplashLoadingController>getController();

        controller.setStage(newStage);
        controller.setController(controller); // guardar o proprio controller para depois poder inserir texto na label
        newStage.setScene(new Scene(root));

//        newStage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
//            if (!isNowFocused) {
//                System.out.println("windows closed  .......");
//                newStage.hide();
//            }
//        });
        newStage.initStyle(StageStyle.UNDECORATED);
        newStage.initModality(Modality.WINDOW_MODAL);
//        newStage.show();

        return newStage;
    }

    public void taskLongLoadImg(){
            String path = "C:\\Users\\jsantos1991\\Pictures\\ImagesTeste";

        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();

        for (final File file : listOfFiles) {
                System.out.println("file:" +file.getName());
                file.setReadOnly();
                ImageView imageView;
                imageView = createImageView(file);
                tile.getChildren().addAll(imageView);
                try {
                    Thread.sleep(300); // 
                } catch (InterruptedException ex) {
                    Logger.getLogger(TestExample.class.getName()).log(Level.SEVERE, null, ex);
                }
        }
    }

    private ImageView createImageView(final File imageFile) {
        // DEFAULT_THUMBNAIL_WIDTH is a constant you need to define
        // The last two arguments are: preserveRatio, and use smooth (slower)
        // resizing

        ImageView imageView = null;
        try {
            final Image image = new Image(new FileInputStream(imageFile), 150, 0, true,
                    true);
            imageView = new ImageView(image);
            imageView.setFitWidth(150);
            imageView.setOnMouseClicked(new EventHandler<MouseEvent>() {

                @Override
                public void handle(MouseEvent mouseEvent) {

                    if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){

                        if(mouseEvent.getClickCount() == 2){
                            try {
                                BorderPane borderPane = new BorderPane();
                                ImageView imageView = new ImageView();
                                Image image = new Image(new FileInputStream(imageFile));
                                imageView.setImage(image);
                                imageView.setStyle("-fx-background-color: BLACK");
                                imageView.setFitHeight(stage.getHeight() - 10);
                                imageView.setPreserveRatio(true);
                                imageView.setSmooth(true);
                                imageView.setCache(true);
                                borderPane.setCenter(imageView);
                                borderPane.setStyle("-fx-background-color: BLACK");
                                Stage newStage = new Stage();
                                newStage.setWidth(stage.getWidth()-400);
                                newStage.setHeight(stage.getHeight()-400);
                                newStage.setTitle(imageFile.getName());
                                Scene scene = new Scene(borderPane,Color.BLACK);
                                newStage.setScene(scene);
                                newStage.show();

                                newStage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
                                    if (!isNowFocused) {
                                        System.out.println("focus out  .......");
                                        newStage.hide();
                                    }
                                });
                            } catch (FileNotFoundException e) {
                                e.printStackTrace();
                            }

                        }
                    }
                }
            });
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
        return imageView;
    }


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Briefly I wanted you to show an indicator of progress and that it was possible to see the TilePane adding images/ to be updated from behind.

  • This article should give you the knowledge you need to implement this, but take a look also at the class documentation Task, that has some "little secrets" about cancelling the Task and about using Platform.runLater(...).

  • Thanks @Douglas I’ll read the article...

1 answer

1


I ran a test from the original code you posted and managed to make a simple progress indicator.

Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();

/* 
 * Coloque o código de carregamento após a abertura da janela principal
 * para não parecer que o programa travou
 */ 
File folder = new File(path);
File[] listOfFiles = folder.listFiles();

// Indicador de progresso em forma de bola    
ProgressIndicator pi = new ProgressIndicator(0.0);
tile.getChildren().add(pi);

/*
 * As Task são usadas para tarefas que não envolvem atualização da UI
 * pois toda atualização de UI deve ser executada pela FX Application Thread
 * Nesse caso deve-se usar o services
 */
Service carregarFotos = new Service() {
    @Override
    protected Task createTask() {
        Task<ObservableList> task = new Task<ObservableList>() {
            @Override
            protected ObservableList call() throws Exception {
                ObservableList<ImageView> itens = FXCollections.observableArrayList();

                // Aqui testei com a mesma imagem 30 vezes.
                // Utilizando um foreach você terá que ver um jeito de
                // mensurar o progresso atual e o total para o updateProgress funcionar
                for(int i = 0; i < 30; i++){
                    ImageView imageView = createImageView(folder);
                    itens.add(imageView);
                    updateProgress(i, 29);
                }
                    // Retorna o array de imagens carregadas
                    return itens;
                }
            };

            return task;
        };
    };

// Atrela o progresso da barra com o progresso da service
pi.progressProperty().bind(carregarFotos.progressProperty());

// Inicia o serviço
carregarFotos.start();

// Quando o service termina a execução pega o resultado da thread
// e adiciona ao tile
carregarFotos.setOnSucceeded((Event event) -> {
    ObservableList<ImageView> itens = (ObservableList<ImageView>) carregarFotos.getValue();
    tile.getChildren().addAll(itens);
});

Here is the photo of the tests during the execution and after:

inserir a descrição da imagem aqui

Browser other questions tagged

You are not signed in. Login or sign up in order to post.