I want to update a JavaFX ProgressBar defined in an FXML file by another class, initialized in a controller thread. Currently it just does not update.
test.fxml
<ProgressBar fx:id="progressBar" prefWidth="5000.0" progress="0.0">
<VBox.margin>
<Insets top="3.0" />
</VBox.margin>
</ProgressBar>
Controller.java
@FXML
public static ProgressBar progressBar = new ProgressBar(0);
MyMain main;
@FXML
private void handleStartWork() throws Exception {
new Thread() {
@Override
public void run() {
try {
main = new MyMain();
main.doIt();
} catch (final Exception v) {
// ...
}
}
}.start();
}
MyMain.java
public void doIt(){
while(...){
Platform.runLater(() -> PoCOverviewController.progressBar.setProgress((count / sum) * 100));
}
}
I already tried different versions in consideration of posts like:
I don't know if it's the right approach to make the ProgressBar static. I just did not want to pass the Object through the workflow.
Update (Xavier Lambros answer): Now i tried it with singleton but it's still not working:
Controller.java
@FXML
public ProgressBar progressBar = new ProgressBar(0);
private static Controller INSTANCE = new Controller();
public static Controller getInstance() {
return INSTANCE;
}
public ProgressBar getProgressBar() {
return progressBar;
}
MyMain.java
public void doIt(){
while(...){
Platform.runLater(() -> Controller.getInstance().getProgressBar()
.setProgress((count / sum) * 100));
}
}
As noted in javafx 8 compatibility issues - FXML static fields, you cannot make a @FXML-annotated field static (and it makes no sense to do so: these fields are inherently properties of the specific controller instance).
To allow the doIt() method access to the progress bar, you could just pass it directly as a parameter:
@FXML
public ProgressBar progressBar ;
MyMain main;
@FXML
private void handleStartWork() throws Exception {
new Thread() {
@Override
public void run() {
try {
main = new MyMain();
main.doIt(progressBar);
} catch (final Exception v) {
// ...
}
}
}.start();
}
and then
public void doIt(ProgressBar progressBar){
while(...){
Platform.runLater(() -> progressBar.setProgress((count / sum) * 100));
}
}
In some circumstances, it might not make sense for the Main class to have a dependency on the JavaFX API. In that case you could just pass a function that updates the progress bar:
@FXML
public ProgressBar progressBar ;
MyMain main;
@FXML
private void handleStartWork() throws Exception {
new Thread() {
@Override
public void run() {
try {
main = new MyMain();
main.doIt(progressBar::setProgress);
} catch (final Exception v) {
// ...
}
}
}.start();
}
and
public void doIt(DoubleConsumer progressUpdate){
while(...){
Platform.runLater(() -> progressUpdate.accept((count / sum) * 100));
}
}
Note that you haven't shown what's happening in your while loop: if you are submitting too many runnables to the FX Application Thread, you might "flood" it and prevent it from updating in a reasonable time. You might consider using a Task, which has specific API for updating a progress field to which the progress bar's progress property can be bound. If it's still not working, you should edit your question to include a MCVE.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With