问题
In a JavaFX application I wish to update a status bar according to some work logic which I've implemented in an other class.
I can't figure out how to combine my desire to pass to work logic to the method (and not to write it inside the task) and to know about the work progress percentage.
This is an example of the controller with the Task:
public class FXMLDocumentController implements Initializable {
@FXML private Label label;
@FXML ProgressBar progressBar;
@FXML
private void handleButtonAction(ActionEvent event) {
Service<Void> myService = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
DatabaseFunctionality.performWorkOnDb();
//updateProgress(1, 1);
} catch (InterruptedException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};
}
};
progressBar.progressProperty().bind(myService.progressProperty());
myService.restart();
}
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
This is the helper class:
public class DatabaseFunctionality {
public static void performWorkOnDb () throws InterruptedException {
for (int i = 1; i <= 100; i++) {
System.out.println("i=" + i);
Thread.sleep(100);
//Update progress
}
}
}
Thank you
回答1:
You have a couple of options here. One is to do as Uluk suggests and expose an observable property in your DatabaseFunctionality
class:
public class DatabaseFunctionality {
private final ReadOnlyDoubleWrapper progress = new ReadOnlyDoubleWrapper();
public double getProgress() {
return progressProperty().get();
}
public ReadOnlyDoubleProperty progressProperty() {
return progress ;
}
public void performWorkOnDb() throws Exception {
for (int i = 1; i <= 100; i++) {
System.out.println("i=" + i);
Thread.sleep(100);
progress.set(1.0*i / 100);
}
}
}
And now in your Task
, you can observe that property and update the task's progress:
Service<Void> myService = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
DatabaseFunctionality dbFunc = new DatabaseFunctionality();
dbFunc.progressProperty().addListener((obs, oldProgress, newProgress) ->
updateProgress(newProgress.doubleValue(), 1));
dbaseFunc.performWorkOnDb();
} catch (InterruptedException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};
}
};
Another option (in case you don't want your data access object to depend on the JavaFX properties API) is to pass the data access object a callback to update the progress. A BiConsumer<Integer, Integer> would work for this:
public class DatabaseFunctionality {
private BiConsumer<Integer, Integer> progressUpdate ;
public void setProgressUpdate(BiConsumer<Integer, Integer> progressUpdate) {
this.progressUpdate = progressUpdate ;
}
public void performWorkOnDb() throws Exception {
for (int i = 1; i <= 100; i++) {
System.out.println("i=" + i);
Thread.sleep(100);
if (progressUpdate != null) {
progressUpdate.accept(i, 100);
}
}
}
}
and then
Service<Void> myService = new Service<Void>() {
@Override
protected Task<Void> createTask() {
return new Task<Void>() {
@Override
protected Void call() throws Exception {
try {
DatabaseFunctionality dbFunc = new DatabaseFunctionality();
dbFunc.setProgressUpdate((workDone, totalWork) ->
updateProgress(workDone, totalWork));
dbaseFunc.performWorkOnDb();
} catch (InterruptedException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
};
}
};
来源:https://stackoverflow.com/questions/34357005/javafx-task-update-progress-from-a-method