Update progress bar and multiple labels from thread

末鹿安然 提交于 2019-12-04 14:52:52
jewelsea

Use multiple Tasks to split the problem into bits. Use a controlling tasks to monitor status and overall progress of subtasks. Use java.util.concurrent classes to manage Task execution, sequencing and data structures such as LinkedBlockingDeque.

This recommended solution is not the simplest solution to your problem, but should offer a good user experience if done well.


For an example of a divide and conquer approach applied to different problems, see the following code samples:

  1. splits a complex process into multiple managed subtasks.
  2. demonstrates management of execution of multiple workers sequentially or in parallel.

A potential simple alternate approach is to use a single Task for the whole process and report your multiple feedback values back to your JavaFX UI by invoking Platform.runLater from your Task code as needed.

See the Task documentation section "A Task Which Modifies The Scene Graph" for an example of this approach.

Here is something which updates multiple labels at once inside a Platform.runLater call.

Platform.runLater(new Runnable() {
  @Override public void run() {
    status.setText("");
    folderCount.setText("");
    fileCount.setText("");
    mp3Count.setText("");
  }
});

And some code which is similar to your example:

import java.util.Arrays;
import java.util.List;
import static javafx.application.Application.launch;
import javafx.application.*;
import javafx.beans.value.*;
import javafx.concurrent.Task;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

public class Mp3Finder extends Application {
  final Label status = new Label();
  final Label folderCount = new Label();
  final Label fileCount = new Label();
  final Label mp3Count = new Label();

  @Override public void start(Stage stage) {
    final GridPane finderResults = new GridPane();
    finderResults.setPrefWidth(400);
    finderResults.setVgap(10);
    finderResults.setHgap(10);
    finderResults.addRow(0, new Label("Status: "),    status);
    finderResults.addRow(1, new Label("# Folders: "), folderCount);
    finderResults.addRow(2, new Label("# Files: "),   fileCount);
    finderResults.addRow(3, new Label("# mp3s: "),    mp3Count);

    final Button finderStarter = new Button("Find mp3s");
    finderStarter.setOnAction(new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent t) {
        startMp3Finder(finderStarter);
      }
    });

    VBox layout = new VBox(10);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10; -fx-font-size: 16;");
    layout.getChildren().setAll(finderStarter, finderResults);
    stage.setScene(new Scene(layout));
    stage.show();
  }

  private void startMp3Finder(final Node starterNode) {
    starterNode.setDisable(true);

    Mp3FinderTask task = new Mp3FinderTask(status, folderCount, mp3Count);
    task.runningProperty().addListener(new ChangeListener<Boolean>() {
      @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean wasRunning, Boolean isRunning) {
        if (!isRunning) {
          starterNode.setDisable(false);
        }
      }
    });

    final Thread thread = new Thread(task , "mp3-finder");
    thread.setDaemon(true);
    thread.start();
  }

  private class Mp3FinderTask extends Task<List<String>> {
    private final Label status;
    private final Label folderCount;
    private final Label mp3Count;

    public Mp3FinderTask(Label status, Label folderCount, Label mp3Count) {
      this.status = status;
      this.folderCount = folderCount;
      this.mp3Count = mp3Count;
    }

    @Override protected List<String> call() throws Exception {
      initFinderResults();

      updateLabelLater(status, "Finding Folders");
      setProgressIndicator(folderCount);
      List folders = findFolders();
      updateLabelLater(folderCount, folders.size() + "");

      updateLabelLater(status, "Finding Files");
      setProgressIndicator(fileCount);
      List files = findFiles(folders);
      updateLabelLater(fileCount, files.size() + "");

      updateLabelLater(status, "Find mp3s");
      setProgressIndicator(mp3Count);
      List mp3s = findMp3s(files);
      updateLabelLater(mp3Count, mp3s.size() + "");

      updateLabelLater(status, "All mp3s Found");

      return mp3s;
    }

    void updateLabelLater(final Label label, final String text) {
      Platform.runLater(new Runnable() {
        @Override public void run() {
          label.setGraphic(null);
          label.setText(text);
        }
      });
    }

    private List<String> findFolders() throws InterruptedException { 
      // dummy implementation
      Thread.currentThread().sleep(1000);
      return Arrays.asList("folder1", "folder2", "folder3");
    }

    private List<String> findFiles(List<String> folders) throws InterruptedException {
      // dummy implementation
      Thread.currentThread().sleep(1000);
      return Arrays.asList("file1", "file2", "file3", "file4", "file5");
    }

    private List<String> findMp3s(List<String> files) throws InterruptedException {
      // dummy implementation
      Thread.currentThread().sleep(1000);
      return Arrays.asList("music1", "music2");
    }

    private void initFinderResults() {
      Platform.runLater(new Runnable() {
        @Override public void run() {
          status.setText("");
          folderCount.setText("");
          fileCount.setText("");
          mp3Count.setText("");
        }
      });
    }

    private void setProgressIndicator(final Label label) {
      Platform.runLater(new Runnable() {
        @Override public void run() {
          label.setGraphic(new ProgressIndicator());
        }
      });
    }
  }

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


See the StackOverflow question on use of Platform.runLater and accessing the UI from a different thread for more information for more information and links to further resources on concurrency in JavaFX.

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