Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display Popup with ProgressBar in JavaFX

How can I display my progress bar through pop up and automatically close if process is finished. Here is my code.

 Task<ProgressForm> task = new Task<ProgressForm>() {
            @Override 
            public ProgressForm call() throws InterruptedException{
                ProgressForm pf = new ProgressForm();
                for (int i = 1; i <= 10; i++) {
                    pf.activateProgressBar(this);
                    updateProgress(i, 10);
                }
            return pf;                
            }
        };

        task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                ProgressForm pf = (ProgressForm)task.getValue();
                pf.getDialogStage().close();
            }
        });

        Thread th = new Thread(task);
        th.run();

Progress form class:

private final Stage dialogStage;
private final ProgressBar pb = new ProgressBar();
private final ProgressIndicator pin = new ProgressIndicator();

public ProgressForm() {
    dialogStage = new Stage();
    dialogStage.initStyle(StageStyle.UTILITY);
    dialogStage.setResizable(false);
    dialogStage.initModality(Modality.APPLICATION_MODAL);

    // PROGRESS BAR
    final Label label = new Label();
    label.setText("alerto");

    pb.setProgress(-1F);
    pin.setProgress(-1F);

    final HBox hb = new HBox();
    hb.setSpacing(5);
    hb.setAlignment(Pos.CENTER);
    hb.getChildren().addAll(pb, pin);

    Scene scene = new Scene(hb);
    dialogStage.setScene(scene);
}

public void activateProgressBar(final Task task) throws InterruptedException {
    pb.progressProperty().bind(task.progressProperty());
    pin.progressProperty().bind(task.progressProperty());
    dialogStage.show();
}

public Stage getDialogStage() {
    return dialogStage;
}

The problem with this code is

  1. if i use .show(), displaying pop up is smooth but NO PROGRESS BAR.
  2. if i use .showAndWait(), displaying pop up requires manual exit for the pop up to close BUT Progress bar displays.

Any thoughts/ideas about this?

like image 563
user3247087 Avatar asked Apr 14 '15 10:04

user3247087


2 Answers

The two rules for multithreading in JavaFX are:

  1. Code which modifies the UI (creates a Stage or changes properties of nodes that are part of a scene graph) must be executed on the JavaFX Application thread. Violating this rule will either throw IllegalStateExceptions or result in unpredictable behavior.
  2. Code which takes a long time to execute should be executed in a background thread (i.e. not the FX Application Thread). Violating this rule will cause the UI to become unresponsive.

Your code violates the first rule, because it calls the ProgressForm constructor in a background thread. You should set up the UI first, show the dialog, and then start the background thread.

Note that there is no need to repeatedly bind the progress properties of the progress bar and indicator to the progress property of the task. Once it is bound, it will remain bound until and unless you unbind it.

It's quite hard to fix your code as it stands, because your background task doesn't actually do anything that takes any time. Here's a version of what you're doing with just a pause:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class ProgressDialogExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        Button startButton = new Button("Start");
        startButton.setOnAction(e -> {
            ProgressForm pForm = new ProgressForm();

            // In real life this task would do something useful and return 
            // some meaningful result:
            Task<Void> task = new Task<Void>() {
                @Override
                public Void call() throws InterruptedException {
                    for (int i = 0; i < 10; i++) {
                        updateProgress(i, 10);
                        Thread.sleep(200);
                    }
                    updateProgress(10, 10);
                    return null ;
                }
            };

            // binds progress of progress bars to progress of task:
            pForm.activateProgressBar(task);

            // in real life this method would get the result of the task
            // and update the UI based on its value:
            task.setOnSucceeded(event -> {
                pForm.getDialogStage().close();
                startButton.setDisable(false);
            });

            startButton.setDisable(true);
            pForm.getDialogStage().show();

            Thread thread = new Thread(task);
            thread.start();
        });

        StackPane root = new StackPane(startButton);
        Scene scene = new Scene(root, 350, 75);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    public static class ProgressForm {
        private final Stage dialogStage;
        private final ProgressBar pb = new ProgressBar();
        private final ProgressIndicator pin = new ProgressIndicator();

        public ProgressForm() {
            dialogStage = new Stage();
            dialogStage.initStyle(StageStyle.UTILITY);
            dialogStage.setResizable(false);
            dialogStage.initModality(Modality.APPLICATION_MODAL);

            // PROGRESS BAR
            final Label label = new Label();
            label.setText("alerto");

            pb.setProgress(-1F);
            pin.setProgress(-1F);

            final HBox hb = new HBox();
            hb.setSpacing(5);
            hb.setAlignment(Pos.CENTER);
            hb.getChildren().addAll(pb, pin);

            Scene scene = new Scene(hb);
            dialogStage.setScene(scene);
        }

        public void activateProgressBar(final Task<?> task)  {
            pb.progressProperty().bind(task.progressProperty());
            pin.progressProperty().bind(task.progressProperty());
            dialogStage.show();
        }

        public Stage getDialogStage() {
            return dialogStage;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
like image 129
James_D Avatar answered Sep 17 '22 19:09

James_D


You can use controlsfx library to display this easily

private void progressDialogue(){
    copyWorker = createWorker();
    ProgressDialog dialog = new ProgressDialog(copyWorker);
    dialog.initStyle(StageStyle.TRANSPARENT);

    dialog.setGraphic(null);
    //stage.initStyle(StageStyle.TRANSPARENT);
    dialog.initStyle(StageStyle.TRANSPARENT);
    //dialog.setContentText("Files are Uploading");
    //dialog.setTitle("Files Uploading");
    //dialog.setHeaderText("This is demo");
    dialog.setHeaderText(null);
    dialog.setGraphic(null);
    dialog.initStyle(StageStyle.UTILITY);
    new Thread(copyWorker).start();        
    dialog.showAndWait();
}


public Task createWorker() {
    return new Task() {
        @Override
        protected Object call() throws Exception {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(100);
                updateMessage("2000 milliseconds");
                updateProgress(i + 1, 10);
            }
            return true;
        }
    };
}

now you need to call the method progressDialogue();

the code is from this video : https://www.youtube.com/watch?v=DK_1YGLI9ig

like image 41
Amirouche Zeggagh Avatar answered Sep 16 '22 19:09

Amirouche Zeggagh