2

I've looked around and I cannot find any decent snippets that show you how to create accurate progress bars. All of the ones I've seen are cheap hacking them by using Thread.sleep(10) to indicate some workload on the thread performing "work". This is extremely inaccurate in some cases because it doesn't actually take into account a threads workload. I also don't want to use a indeterminate progress bar because those look bad.

My question is: How can you create an accurate progress bar (non-indeterminate) that runs parallel with the thread doing all the "work" in this case writing several thousand images to a directory. If you don't know the work load of the thread and you don't know how long it will take to actually dump all of them. What is the best way to approach this? I'm trying to make this realistic and not showing the progress bar just for cosmetics.

So let's say I have a program like this.

      @FXML
  private void dump(ActionEvent e) {
        try {
                 if (e.getSource() == spriteDumpMI) {

                    Thread thread = new Thread(() -> {

                          try (Cache cache = new Cache(FileStore.open(Constants.CACHE_PATH))) {
                                ReferenceTable table = ReferenceTable.decode(Container
                                            .decode(cache.getStore().read(255, 8)).getData());

                                Platform.runLater(() -> {
                                      createTask(10, table.capacity());
                                });


                                for (int i = 0; i < table.capacity(); i++) {
                                      if (table.getEntry(i) == null)
                                            continue;

                                      Container container = cache.read(8, i);
                                      Sprite sprite = Sprite.decode(container.getData());

                                      File dir = new File(Constants.SPRITE_PATH);

                                      if (!dir.exists()) {
                                            dir.mkdir();
                                      }

                                      for (int frame = 0; frame < sprite.size(); frame++) {
                                            File file = new File(Constants.SPRITE_PATH,
                                                        i + "_" + frame + ".png");
                                            BufferedImage image = sprite.getFrame(frame);

                                            ImageIO.write(image, "png", file);
                                      }

                                }
                          } catch (FileNotFoundException e1) {
                                e1.printStackTrace();
                          } catch (IOException e1) {
                                e1.printStackTrace();
                          }

                    });

                    thread.start();

              }
        } catch (Exception ex) {
              ex.printStackTrace();
        }
  }

The program is simple, basically it writes all of the sprites that are found in an archive (can be several thousand images) and writes all of them to a directory so the user can use them.

I'm updating my progress bar by using this.

                                    Platform.runLater(() -> {
                                      // this is bad
                                      createTask(10, table.capacity());
                                });

I understand I could update the progress bar in the loop, but I'm not sure how to do that without creating a ton of threads and new tasks (which is also really bad)

And the method createTask

      private void createTask(int workload, int max) {

        Task<Boolean> task = taskCreator(workload, max);

        progressBar.setVisible(true);
        progressI.setVisible(true);

        progressBar.progressProperty().unbind();
        progressBar.progressProperty().bind(task.progressProperty());

        progressI.progressProperty().unbind();
        progressI.progressProperty().bind(task.progressProperty());

        new Thread(task).start();
  }

  private Task<Boolean> taskCreator(int workload, int max) {
        return new Task<Boolean>() {

              @Override
              protected Boolean call() throws Exception {

                    progressText.setText("In Progress");
                    progressText.setFill(Color.WHITE);

                    for (int index = 0; index < max; index++) {
                          Thread.sleep(workload);

                          updateProgress(index, max);
                    }

                    progressText.setText("Complete!");
                    progressText.setFill(Color.GREEN);

                    Thread.sleep(1000);

                    progressBar.setVisible(false);
                    progressI.setVisible(false);
                    progressText.setText("");

                    return true;

              }

        };
  }

1 Answers1

0

Wish this could help.

 @FXML
 private void dump(ActionEvent e) {

    try {
             if (e.getSource() == spriteDumpMI) {

                progressBar.setVisible(true);
                progressI.setVisible(true);

                progressBar.progressProperty().unbind();
                progressBar.progressProperty().bind(task.progressProperty());

                progressI.progressProperty().unbind();
                progressI.progressProperty().bind(task.progressProperty());

                progressText.textProperty().unbind();
                progressText.textProperty().bind(task.messageProperty());
                progressText.setFill(Color.GREEN);

                Task task = new Task<Boolean>() {

                  @Override
                  protected Boolean call() throws Exception {
                        updateMessage("In Progress");

                        try (Cache cache = new Cache(FileStore.open(Constants.CACHE_PATH))) {
                                ReferenceTable table = ReferenceTable.decode(Container
                                            .decode(cache.getStore().read(255, 8)).getData());
                                long count;
                                for (int i = 0; i < table.capacity(); i++) {
                                      if (table.getEntry(i) == null)
                                            continue;

                                      Container container = cache.read(8, i);
                                      Sprite sprite = Sprite.decode(container.getData());

                                      File dir = new File(Constants.SPRITE_PATH);

                                      if (!dir.exists()) {
                                            dir.mkdir();
                                      }

                                      for (int frame = 0; frame < sprite.size(); frame++) {
                                            count++;
                                      }

                                }

                                int current;
                                for (int i = 0; i < table.capacity(); i++) {
                                      if (table.getEntry(i) == null)
                                            continue;

                                      Container container = cache.read(8, i);
                                      Sprite sprite = Sprite.decode(container.getData());

                                      File dir = new File(Constants.SPRITE_PATH);

                                      if (!dir.exists()) {
                                            dir.mkdir();
                                      }

                                      for (int frame = 0; frame < sprite.size(); frame++) {
                                            File file = new File(Constants.SPRITE_PATH,
                                                        i + "_" + frame + ".png");
                                            BufferedImage image = sprite.getFrame(frame);

                                            ImageIO.write(image, "png", file);
                                            current++;
                                            updateProgress(current, count);
                                      }

                                }
                                updateMessage("Complete!");
                                Platform.runLater(() -> {
                                    progressText.setFill(Color.GREEN);
                                });
                          } catch (FileNotFoundException e1) {
                                e1.printStackTrace();
                                updateMessage("failed!");
                                Platform.runLater(() -> {
                                    progressText.setFill(Color.GREEN);
                                });
                          } catch (IOException e1) {
                                e1.printStackTrace();
                                updateMessage("failed!");
                                Platform.runLater(() -> {
                                    progressText.setFill(Color.GREEN);
                                });
                          }
                        return true;

                      }

                };

          }
          task.setOnSucceeded(e ->{
                progressBar.setVisible(false);
                progressI.setVisible(false);
                progressText.setText("");
          });
          task.setOnFailed(e ->{
                progressBar.setVisible(false);
                progressI.setVisible(false);
                progressText.setText("");
          });

          new Thread(task).start();
    } catch (Exception ex) {
          ex.printStackTrace();
    }

}

Rhain
  • 197
  • 1
  • 10
  • yeah that's not gonna work, look at the scope of the task instance you created and where you're trying to access it. i appreciate the attempt though –  May 13 '16 at 07:46
  • what are the scope of the task should be? – Rhain May 13 '16 at 07:56
  • you're trying to get 'task.progressProperty()' when its above the "task" instance. I think i figured it out, ill post in a sec. –  May 13 '16 at 08:29
  • yeah haha, i edited it a little bit but works fine now, thanks man –  May 13 '16 at 09:15