I attempted to update a ProgressBar
value within a for loop. Its progress should update every 100 miliseconds but unfortunately it didn't work! Here's the code:
pb = new ProgressBar(0);
Button btn = new Button("Start!");
btn.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event) {
for(int i = 0; i <=100; i++){
position = i;
Platform.runLater(new Runnable(){
@Override
public void run() {
pb.setProgress(position);
System.out.println("Index: "+position);
}
});
try{
Thread.sleep(100);
}catch(Exception e){ System.err.println(e); }
}
}
});
Question 1: I was expecting the above code to update the progressbar every 100 miliseconds but it didn't work. Why?
Question 2: I called System.out.println("Index: "+position);
within the loop. I assumed that the output should be 1..2..3..4...
but I was wrong. The output is something like this:
Index: 100
Index: 100
Index: 100
Index: 100
Index: 100
Index: 100
Index: 100
An alternative to re-inventing the wheel by manually calculating and setting the progressProperty of the bar is to use a Task: it has a progressProperty that auto-calculates the relative amount and guarantees to update on the FX-application thread, such that it is safe to bind any scene-related property to.
Something like:
Obviously, this is the very barest snippet - see Task for examples that play nicely with cancelling/interrupting the thread.
Background
Platform.runLater()
is called to execute something on theJavaFX Application thread
when you are on some other thread. You are running it every 100ms when you are already on the JavaFX application thread adding all these items in queue, because the thread is already busy running the loop and sleeping :)So it runs everything in queue after the thread is free to execute them i.e. after finishing the loop.
There is another problem, ProgressBar has a progressproperty whose value can be between 0 and 1, where 0 represents 0% and 1 represents 100%. If you want to update the progress bar, you would want to set the progress with values between 0.1 to 1.0.
How to FIX
You should start a new Thread on the button's action and let it handle the loop. You can use
Platform.runLater
inside this thread, without choking the JavaFX application thread.I would run something as below :
Note : This answer stresses more on where the OP went wrong and how he can rectify it. If you are on JavaFX, you would want to use better approaches i.e. using
Task
and itsupdateProgress()
for updating the progress of the ProgressBar as stated by @kleopatra in her solution.