0

I've been searching for some time now on how to create multiple tasks and have them run one after the other. Here is the java code:

public class Main extends Application {

    DropShadow shadow = new DropShadow();
    Button button = new Button("Start");
    Task<Integer> task;
    Task<Integer> task2;
    Label label1 = new Label("Status: NOT STARTED");
    ProgressBar bar = new ProgressBar(0);
    ProgressIndicator pi = new ProgressIndicator(0);
    Thread th = new Thread();

    public void start(Stage stage) {
        task = new Task<Integer>() {
            protected Integer call() throws Exception {
                int iterations;
                for (iterations = 0; iterations < 1001; iterations++) {
                    if (isCancelled()) {
                        updateMessage("Cancelled");
                        break;
                    }
                    updateProgress(iterations, 1001);
                    updateMessage("Test");

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException interrupted) {
                        if (isCancelled()) {
                            //updateMessage("Cancelled");
                            break;
                        }
                    }
                }
                return iterations;
            }
        };

        task2 = new Task<Integer>() {
            protected Integer call() throws Exception {
                int iterations;
                for (iterations = 0; iterations < 1001; iterations++) {
                    if (isCancelled()) {
                        updateMessage("Cancelled");
                        break;
                    }
                    updateProgress(iterations, 1001);
                    updateMessage("Test");

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException interrupted) {
                        if (isCancelled()) {
                            //updateMessage("Cancelled");
                            break;
                        }
                    }
                }
                return iterations;
            }
        };

    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){

        public void handle(WorkerStateEvent arg0) {
            label1.setText("Done");
            new Thread(task2).start();
        }
    });

        Group root = new Group();
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Progress Controls");

        final Slider slider = new Slider();
        slider.setMin(0);
        slider.setMax(50);

        bar.progressProperty().bind(task.progressProperty());
        pi.progressProperty().bind(task.progressProperty());
        label1.textProperty().bind(task.messageProperty());

        button.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            public void handle(MouseEvent e) {
                button.setEffect(shadow);
                new Thread(task).start();

            }
        });

        button.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler <MouseEvent>() {
            public void handle(MouseEvent arg0) {
                button.setEffect(null);
            }
        });

        final HBox hb = new HBox();
        hb.setSpacing(5);
        hb.setAlignment(Pos.CENTER);
        hb.getChildren().addAll(bar, pi, button, label1);
        scene.setRoot(hb);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

Basically I want to have two progress bars and around 5 tasks in total. One progress bar will be for the current task running and the other one for the overall progress. Once task1 is done, I want it to run task 2 and update the progress bar back to zero while increasing the other progress one. However, once I create a new Thread for the other task nothing in the GUI gets updated.

Thanks in advance.

EDIT: I have fixed the part of the code that starts the second task. However, I have these questions:

  1. How can I create an overall progress bar that gets updated as different tasks get completed?

  2. How can I dynamically reset and update the single progress bar for each individual task once each new task is launched? Do I have to create various ProgressBar objects for this?

Wilo Maldonado
  • 551
  • 2
  • 11
  • 22
  • Your EventHandler creates a new Thread for task2, but it never starts the thread or stores a reference to it anywhere. – Solomon Slow Apr 09 '14 at 18:47
  • just fixed that. However how can I reset the progress bars to display the status from task 2? – Wilo Maldonado Apr 09 '14 at 18:53
  • @jameslarge - I'm guessing I'll have to modify the bar.progressProperty().bind(task.progressProperty()); but how can I dynamically change that once 'task' is done and now 'task2' is running? – Wilo Maldonado Apr 09 '14 at 19:01
  • possible duplicate of [How to reset progress indicator between tasks in JavaFX2?](http://stackoverflow.com/questions/16368793/how-to-reset-progress-indicator-between-tasks-in-javafx2) – jewelsea Apr 09 '14 at 19:10
  • @jewelsea - Possible but I just found a solution – Wilo Maldonado Apr 09 '14 at 19:11

2 Answers2

7

Your solution works. It's marginal, but I would suggest it's slightly better to have a solution where task1 doesn't know about task2. You can do this by:

  1. Using an onSucceeded handler to "rebind" the progress bar
  2. Using a single threaded executor and submitting both tasks to it

For the "overall progress", you could create a DoubleBinding that represents the total progress.

public class Main extends Application {

    DropShadow shadow = new DropShadow();
    Button button = new Button("Start");
    Task<Integer> task;
    Task<Integer> task2;
    Label label1 = new Label("Status: NOT STARTED");
    ProgressBar bar = new ProgressBar(0);
    ProgressIndicator pi = new ProgressIndicator(0);
    Thread th = new Thread();

    public void start(Stage stage) {
        task = new Task<Integer>() {
            protected Integer call() throws Exception {
                int iterations;
                for (iterations = 0; iterations < 1001; iterations++) {
                    if (isCancelled()) {
                        updateMessage("Cancelled");
                        break;
                    }
                    updateProgress(iterations, 1001);
                    updateMessage("Test");

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException interrupted) {
                        if (isCancelled()) {
                            //updateMessage("Cancelled");
                            break;
                        }
                    }
                }
                return iterations;
            }
        };

        task2 = new Task<Integer>() {
            protected Integer call() throws Exception {
                int iterations;
                for (iterations = 0; iterations < 1001; iterations++) {
                    if (isCancelled()) {
                        updateMessage("Cancelled");
                        break;
                    }
                    updateProgress(iterations, 1001);
                    updateMessage("Test");

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException interrupted) {
                        if (isCancelled()) {
                            //updateMessage("Cancelled");
                            break;
                        }
                    }
                }
                return iterations;
            }
        };

    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){

        public void handle(WorkerStateEvent arg0) {
            label1.setText("Done");
            bar.progressProperty().unbind();
            bar.progressProperty().bind(task2.progressProperty());
        }
    });

    final int numTasks = 2 ;

    DoubleBinding totalProgress = Bindings.createDoubleBinding(new Callable<Double>() {
        @Override
        public Double call() {
            return ( Math.max(0, task1.getProgress())
                   + Math.max(0, task2.getProgress()) ) / numTasks ;
        },
        task1.progressProperty(), task2.progressProperty());

   pi.progressProperty().bind(totalProgress);

        Group root = new Group();
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Progress Controls");

        final Slider slider = new Slider();
        slider.setMin(0);
        slider.setMax(50);

        bar.progressProperty().bind(task.progressProperty());
        //  pi.progressProperty().bind(task.progressProperty());
        label1.textProperty().bind(task.messageProperty());

        final ExecutorService exec = Executors.newSingleThreadExecutor();

        button.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            public void handle(MouseEvent e) {
                button.setEffect(shadow);
                exec.submit(task);
                exec.submit(task2);
            }
        });

        button.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler <MouseEvent>() {
            public void handle(MouseEvent arg0) {
                button.setEffect(null);
            }
        });

        final HBox hb = new HBox();
        hb.setSpacing(5);
        hb.setAlignment(Pos.CENTER);
        hb.getChildren().addAll(bar, pi, button, label1);
        scene.setRoot(hb);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Nothing big: just notice I put the same two lines (`bar.progressProperty().unbind();` and `bar.progressProperty().bind(...);`) in an EventHandler which was not part of the task1 object. You had those as part of the succeeded(...) method of the task1 object. If you wanted to refactor it so that task1 was an inner class, or top-level class, instead of an anonymous class, the way I did it you wouldn't have to pass a reference to task2 to that class. (In other words, task2 is not part of the implementation of task1.) – James_D Apr 10 '14 at 00:14
0

I found my own solution but not sure if it's the best implementation.

Basically I just used the succeed method from Task and unbinded the progressbar and then binded it again with the new task.

task = new Task<Integer>() {
    protected Integer call() throws Exception {
        int iterations;
        for (iterations = 0; iterations < 1001; iterations++) {
            if (isCancelled()) {
                updateMessage("Cancelled");
                break;
            }
            updateProgress(iterations, 1001);
            updateMessage("Test");

            try {
                Thread.sleep(10);
            } catch (InterruptedException interrupted) {
                if (isCancelled()) {
                    //updateMessage("Cancelled");
                    break;
                }
            }
        }
        return iterations;
    }

    @Override
    protected void succeeded() {
        super.succeeded();
        updateMessage("Done");
        bar.progressProperty().unbind();
        bar.progressProperty().bind(task2.progressProperty());
        new Thread(task2).start();
    }
};

That solved the issue on how to update the progress bar for each individual task

Wilo Maldonado
  • 551
  • 2
  • 11
  • 22