I have one progress indicator on my main screen UI that is shared by various tabs and services. Each TabController has its own instance of Service. In my MainController class, for each tab I have bound each Service's progress property to the ProgressIndicator.
@FXML
Region veil;
@FXML
ProgressIndicator progressDial;
progressDial.progressProperty().bind(tabController.commandService.progressProperty());
veil.visibleProperty().bind(tabController.commandService.runningProperty());
progressDial.visibleProperty().bind(tabController.commandService.runningProperty());
tabController.commandService.messageProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> ov, String t, String newValue) {
addCommentary(newValue);
}
});
However I see that after the first service uses it, the progress dial does not appear for the execution of subsequent services or tasks. I am wondering if I am misusing the ProgressIndicator since each Service probably runs concurrently. I am guessing that the progress wasn't reset after the first finished. How do I reset it? The progress property is read only.
ReadOnlyDoubleProperty progressProperty() Gets the ReadOnlyDoubleProperty representing the progress.
And calling updateProgress(0) does nothing to make the dial reappear.
I tried to explicitly reset it using the ProgressIndicator as a global
mainController.progressDial.setProgress(0);
but this failed
java.lang.RuntimeException: A bound value cannot be set.
at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:159)
I could be mistaken, but I think this is a fault in the JavaFX UI controls design. Updating progress to 0 should reset the progress Indicator.
There is a bit of writing in my answer because it's not exactly clear to me from your question what is going wrong with your instance. Hopefully either the explanation or the sample code in the answer is useful.
You are slightly mistaken. You have bound the progress of the indicator to the progress of a task. The task is completed and progress is 1. Now if you want to re-use the same indicator for another task or make it measure the progress of something else, you have to first stop it from measuring the progress of the original task. To disassociate the progress indicator for the original task, unbind it's progress. Once the progress indicator's progress is no longer bound to the original task's progress, you are free to set the indicator to whatever value you want, or bind it to something else.
Similarly, you can only bind the progress indicator's progress to one thing at a time (unless you bi-directionally bind the indicator, which you can't do with task progress because task progress is read only and bi-directionally binding to multiple task progress values would be incorrect anyway as each task would be at a different progress point).
I'm not sure from your description why the dial would disappear in the first place so that it would need to reappear. Normally, when a progress indicator's progress reaches 1, it still stays visible reporting fully completed progress, it doesn't automatically disappear. You are likely setting the visibility of the indicator to false or modifying it's opacity to zero. Both of those properties have nothing to do with the actual progress measured by the indicator. Or maybe you are removing the indicator from the displayed scene. If you are modifying visibility and setting the indicator to invisible after a task is completed and you want to subsequently see it again to measure the progress of another task, then you will need to make sure it is in the scene, with opacity > 0 and visibility set to true.
A suggestion
You can only run a task once, so after it is done, it doesn't make a lot of sense to set it's progress back to zero if it had already made some progress.
Property types
A progress indicator's progress property is a plain
DoubleProperty
, not aReadOnlyDoubleProperty
, so it is directly settable (as long as it is not bound to another value).A task's progress property which is read only and must be changed via updateProgress. The task's progress property was likely made read only so that updates to it can be ensured to be threadsafe by special code in the
updateProgress
routine.Sample Code
Consider the following code which (I believe) accomplishes the intent of what you are trying to do. The code simulates running a triathlon where each stage (swim, bike, run) of the triathlon is a separate task. While a triathlon is being run, a progress indicator shows the progress of each stage of the triathlon. When the triathlon completes the progress indicator fades away until a new triathlon is started. Sorry the sample is so lengthy, I found it hard to come up with something more concise.
Update for Additional Question
Run the events in parallel using the mechanism defined in Creating multiple parallel tasks. Create a single progress indicator for your overall olympics progress and bind it to the progress of the sum of progress for all tasks using the low level binding api.
Here is a another sample which demonstrates use of the overallProgress
DoubleBinding
.