6

I try to understand how to update a ProgressBar in a multithreaded environment. I'm doing something wrong here but I don't see what it is. This should simply fill up the bar every 3sec but it doesn't:

    Task<Void> task = new Task<Void>(){
        @Override
        public Void call(){
            for (int i = 1; i < 10; i++)    {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
                updateProgress(i , 10);
            }
        return null;                
        }
    };

    updProg = new ProgressBar();
    updProg.progressProperty().bind(task.progressProperty());

    Thread th = new Thread(task);
    th.setDaemon(true);
    th.start();

What am I missing?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Chromos
  • 1,801
  • 6
  • 20
  • 26

4 Answers4

11

Your sample works fine for me.

The sample fills the bar a little bit every 3 seconds, completely filling the bar in half a minute.

I just wrapped it in some scaffolding code to make it executable and it worked without change (java7u15, win7).

simpletaskprogress

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ProgressTest extends Application {
  public static void main(String[] args) { Application.launch(args); }
  @Override public void start(Stage stage) {
    Task<Void> task = new Task<Void>() {
      @Override public Void call() {
        for (int i = 0; i < 10; i++) {
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            Thread.interrupted();
            break;
          }
          System.out.println(i + 1);
          updateProgress(i + 1, 10);
        }
        return null;
      }
    };

    ProgressBar updProg = new ProgressBar();
    updProg.progressProperty().bind(task.progressProperty());

    Thread th = new Thread(task);
    th.setDaemon(true);
    th.start();

    StackPane layout = new StackPane();
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
    layout.getChildren().add(updProg);

    stage.setScene(new Scene(layout));
    stage.show();
  }
}

Perhaps you have been using some early access version of Java 8 which had a bug in it (now fixed) around ProgressBar updates.

RT-29018 ProgressBar and ProgressIndicator disappear when progressProperty is updated

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • I copied your code and it runs just perfectly. Did I integrate it wrong somehow? Im using it in a sub-class and have to access the progressbar in a static way. could this cause some trouble? Im using 7v17 btw – Chromos Mar 20 '13 at 12:18
  • The fix to RT-29018 will be available in a [Java 8 preview release](http://jdk8.java.net/download.html) within the next couple of weeks. – jewelsea Mar 21 '13 at 15:28
  • Maybe you should add "=" to the loop condition, so the progressbar can be filled at the end. – O.Badr May 03 '16 at 21:59
  • Yep Badr, I had just copy and pasted the code from the question and don't think I waited around 30 seconds to see the bar not fill up. I changed the loop to use a zero based loop rather than a non-standard 1 based loop https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html. I also set up proper handling in case the thread gets interrupted. – jewelsea May 03 '16 at 22:15
1

Are you using the latest JDK 8 Early-Access? If so, see this bug report I filed: http://javafx-jira.kenai.com/browse/RT-29018

Basically, in a recent release of the early-access build, they made some changes in the skins and css. This caused a hidden bug to be revealed in which child nodes which are dirtier than parent nodes but both need repainting in the same pulse, the parent's dirty level ends up overwriting the child nodes dirty level.

This causes the progress to not show, and in fact, for me the progressBar became entirely invisible, as soon as updateProgress was called from the task. They have a patch in place, I don't know when this will go through.

A work-around, either use jdk7 while waiting on the patch, or you can do what I did and apply this from the old css into your css stylesheet:

/*hack to get progress bar working. From: JDK7u17 jfxrt.jar!/com/sun/javafx/scene/control/skin/caspian/caspian.css */

/*******************************************************************************
 *                                                                             *
 * ProgressBar                                                                 *
 *                                                                             *
 ******************************************************************************/

.progress-bar {
    -fx-skin: "com.sun.javafx.scene.control.skin.ProgressBarSkin";
    -fx-background-color:
        -fx-box-border,
        linear-gradient(to bottom, derive(-fx-color,30%) 5%, derive(-fx-color,-17%));
    -fx-background-insets: 0, 1;
    -fx-indeterminate-bar-length: 60;
    -fx-indeterminate-bar-escape: true;
    -fx-indeterminate-bar-flip: true;
    -fx-indeterminate-bar-animation-time: 2;
    -fx-focus-traversable: true;
}

.progress-bar .bar {
    -fx-background-color:
        -fx-box-border,
        linear-gradient(to bottom, derive(-fx-accent,95%), derive(-fx-accent,10%)),
        linear-gradient(to bottom, derive(-fx-accent,38%), -fx-accent);
    -fx-background-insets: 0, 1, 2;
    -fx-padding: 0.416667em; /* 5 */
}

.progress-bar:indeterminate .bar {
    -fx-background-color: linear-gradient(to left, transparent, -fx-accent);
}

.progress-bar .track {
     -fx-background-color:
        -fx-box-border,
        linear-gradient(to bottom, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
    -fx-background-insets:  0, 1;
}

.progress-bar:disabled {
    -fx-opacity: 1.0
}
Edub Kendo
  • 473
  • 2
  • 11
  • thx for your answer. The thing is Im actually using jre 7v17. Tested it in win7 and ubuntu and it did not work. But the exact example from jewelsas answer worked just fine. It must have something to do how I implemented the ProgressBar – Chromos Mar 21 '13 at 11:38
  • how to use this css ? – Noor Hossain Sep 06 '21 at 17:30
0

If you defined updProg in the FXML file, then the problem could be the initialization here.

try to just remove this line:

updProg = new ProgressBar();
Chaiavi
  • 769
  • 9
  • 23
  • Please, if someone downvote, keep a comment about it, so the poster can correct his answer, and can get upvote. – O.Badr May 03 '16 at 20:49
0
 Timeline updateProgressBar = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                      /*Where Seconds and TotalSeconds are counter and total
                      respectively, also put somewhere Seconds++ or 
                      however you want to update progress. This time line 
                      will reapit each second */
                      progressBar.setProgress(Seconds / TotalSeconds);
                }
    }));
    updateProgressBar.setCycleCount(Timeline.INDEFINITE);
    updateProgressBar.play();
Dan
  • 171
  • 1
  • 6