Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javafx Task - update progress from a method

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

like image 257
Ido Gal Avatar asked Dec 18 '15 13:12

Ido Gal


1 Answers

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;
            }
        }; 
    }            
};
like image 191
James_D Avatar answered Oct 11 '22 07:10

James_D