Javafx Task - update progress from a method

流过昼夜 提交于 2021-02-06 13:22:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!