从线程更新进度条和多个标签

时间:2013-03-02 12:19:28

标签: progress-bar javafx-2 javafx worker

我正在开发一个JavaFX应用程序,让用户选择一个文件夹,然后解析它的内容以查找MP3文件并阅读它们的元数据。

我使用Swing工作虽然我发现很难让用户界面看起来很好。因此,我试图在JavaFX中做同样的事情。

在最初的Swing应用程序中,我创建了一个线程,该线程开始解析用户选择的文件夹中的文件。它的工作原理如下:

  1. 找出要解析的文件总数 - 文件数和文件夹数在UI中的两个单独标签中连续显示
  2. 解析所有文件以查找哪些文件是MP3文件并存储元数据 - 在UI中的标签中连续显示找到的MP3文件数
  3. 同时更新标签,显示发生的事件的状态,以及反映上述两个步骤进度的进度条。第一步的进度占总进度的30%,而第二步则占另外70%的进展。

    我找到了一个如何将任务绑定到进度条的示例,但我还需要更新四个标签:状态,文件数,文件夹数和MP3数。

    我相信我可以使用updateMessage处理其中一个标签,但我不知道如何管理其他三个标签。

1 个答案:

答案 0 :(得分:8)

使用多个任务将问题拆分为多个位。使用控制任务来监视子任务的状态和总体进度。使用java.util.concurrent类来管理Task执行,排序和数据结构,例如LinkedBlockingDeque

这个推荐的解决方案不是解决您问题的最简单的解决方案,但如果做得好,应该提供良好的用户体验。


有关应用于不同问题的分而治之法的示例,请参阅以下代码示例:

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

  3. 一种潜在的简单替代方法是对整个过程使用单个Task,并根据需要从任务代码中调用Platform.runLater,将多个反馈值报告回JavaFX UI。

    有关此方法的示例,请参阅Task documentation section "A Task Which Modifies The Scene Graph"

    这是在Platform.runLater电话中同时更新多个标签的内容。

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

    和一些与你的例子相似的代码:

    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); }
    }
    

    mp3finder


    有关更多信息,请参阅use of Platform.runLater and accessing the UI from a different thread for more information上的StackOverflow问题,以及指向JavaFX中有关并发性的更多资源的链接。