3

ユーザーがフォルダーを選択し、その内容を解析してMP3ファイルを見つけてメタデータを読み取るJavaFXアプリケーションに取り組んでいます。

ユーザーインターフェイスの見栄えを良くするのは難しいと思いましたが、これをSwingで動作させました。したがって、私はJavaFXで同じことをしようとしています。

元の Swing アプリでは、ユーザーが選択したフォルダー内のファイルの解析を開始するスレッドを作成します。それはこのように動作します:

  1. 解析するファイルの総数を調べる - ファイルの数とフォルダーの数は、UI の 2 つの別々のラベルで継続的に表示されます
  2. すべてのファイルを解析して MP3 ファイルを見つけ、メタデータを保存する - 見つかった MP3 ファイルの数は、UI のラベルに継続的に表示されます

同時に、何が起こっているかのステータスを示すラベルと、上記の 2 つの手順の進行状況を反映する進行状況バーが更新されます。最初のステップの進捗は全体の進捗の 30 % を占め、2 番目のステップは残りの 70 % を占めます。

タスクを進行状況バーにバインドする方法の例を見つけましたが、ステータス、ファイル数、フォルダー数、MP3 数の 4 つのラベルも更新する必要があります。

ラベルの 1 つは で処理できると思いますが、他の 3 つのラベルの処理updateMessage方法はわかりません。

4

1 に答える 1

9

複数のタスクを使用して、問題をビットに分割します。制御タスクを使用して、サブタスクのステータスと全体的な進行状況を監視します。java.util.concurrentクラスを使用して、タスクの実行、順序付け、およびLinkedBlockingDequeなどのデータ構造を管理します。

この推奨される解決策は、問題に対する最も単純な解決策ではありませんが、うまく行けば、優れたユーザーエクスペリエンスを提供するはずです。


さまざまな問題に適用される分割統治アプローチの例については、次のコードサンプルを参照してください。

  1. 複雑なプロセスを複数の管理対象サブタスクに分割します
  2. 複数のワーカーの実行の管理を順次または並行して示します。

考えられる単純な代替アプローチは、プロセス全体に単一を使用し、必要に応じてタスクコードからTask呼び出すことにより、複数のフィードバック値をJavaFXUIに報告することです。Platform.runLater

このアプローチの例については、タスクのドキュメントセクション「シーングラフを変更するタスク」を参照してください。

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


詳細およびJavaFXでの同時実行に関するその他のリソースへのリンクについては、Platform.runLaterの使用および別のスレッドからのUIへのアクセスに関するStackOverflowの質問を参照してください。

于 2013-03-02T19:43:41.073 に答える