JavaFXでTaskの進捗率をProgressBarに表示

JavaFXで「Start」ボタンをクリックしたら非同期のTaskを実行して、その進捗率をProgressBarに表示する画面を作成

  • 起動直後の画面

  • startボタンをクリック、2つのTaskがそれぞれ動作している画面(ProgressBarがそれぞれ動く、でも右端に進捗率の文言を設定しているつもりが表示されない?

  • bindの実装を修正して右端に文言が表示されるようになりました

  • Task終了後の画面

  • 実装はこんな感じ(修正しました)
package progresssample;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class ProgressSample extends Application {
    
    @Override
    public void start(Stage primaryStage) {      
        VBox vBox = new VBox();
        vBox.setSpacing(5);
        vBox.setAlignment(Pos.CENTER);
        final Scene scene = new Scene(vBox, 300, 250);
        // ★1行目
        HBox hBox1 = new HBox();
        hBox1.setSpacing(5);
        Text title1 = new Text("Task1");
        Button btn1 = new Button("start");
        final ProgressBar bar1 = new ProgressBar(0);
        final Text text1 = new Text("ready");
        hBox1.setAlignment(Pos.CENTER);
        hBox1.getChildren().addAll(title1, btn1, bar1, text1);
        btn1.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                final Task<String> task1 = getTask1();  // ★1Taskを作成                
                bar1.progressProperty().unbind();
                bar1.progressProperty().bind(task1.progressProperty()); // ★2バインド指定
                text1.textProperty().bind(task1.messageProperty()); // ★5txtのバインド指定
                final ExecutorService exe = Executors.newSingleThreadExecutor();
                exe.submit(task1);   // ★3Task実行開始
                task1.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, 
                    new EventHandler<WorkerStateEvent>() {
                    @Override
                    public void handle(WorkerStateEvent t) {
                        exe.shutdown();     // ★4
                    }
                });
            }
        });
        
        // ★2行目
        HBox hBox2 = new HBox();
        hBox2.setSpacing(5);
        Text title2 = new Text("Task2");
        Button btn2 = new Button("start");
        final ProgressBar bar2 = new ProgressBar(0);
        final Text text2 = new Text("ready");
        hBox2.setAlignment(Pos.CENTER);
        hBox2.getChildren().addAll(title2, btn2, bar2, text2);
        btn2.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                final Task<String> task2 = getTask2();
                bar2.progressProperty().unbind();
                bar2.progressProperty().bind(task2.progressProperty());
                text2.textProperty().bind(task2.messageProperty());                        
                final ExecutorService exe = Executors.newSingleThreadExecutor();
                exe.submit(task2);
                task2.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED, 
                    new EventHandler<WorkerStateEvent>() {
                    @Override
                    public void handle(WorkerStateEvent t) {
                        exe.shutdown();
                    }
                });
            }
        });
        vBox.getChildren().add(hBox1);
        vBox.getChildren().add(hBox2);
        primaryStage.setTitle("Progress Smaple");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    private Task<String> getTask1() {
        return new Task<String>() {
            @Override
            protected String call() throws Exception {
                updateMessage("start task1");
                int i;
                for (i = 1; i <= 10; i++) {
                    updateProgress(i, 10);  // ★1-1ここでTaskのprogressを設定
                    TimeUnit.SECONDS.sleep(1);
                    updateMessage(String.format("running %d/%d", i, 10));   // ★1-2ここでTaskのmessageを設定
                }
                updateMessage("task1 done");
                return "Done";
            }
        };
    }

    private Task<String> getTask2() {
        return new Task<String>() {
            @Override
            protected String call() throws Exception {
                updateMessage("start task2");
                int i;
                for (i = 1; i <= 20; i++) {
                    updateProgress(i, 20);
                    TimeUnit.SECONDS.sleep(1);
                    updateMessage(String.format("running %d/%d", i, 20));
                }
                updateMessage("task2 done");
                return "Done";
            }
        };
    }
}

★5のTaskのMessageを取得して、画面右のTextに設定しているが画面に表示されない?
textのbind指定もpropertyを使用するようです。

text1.textProperty().bind(task1.messageProperty()); // ★5txtのバインド指定

次はこれをLambda式で実装しよう!