2013-03-02 1 views
3

사용자가 폴더를 선택하고 MP3 파일을 찾고 해당 메타 데이터를 읽는 내용을 구문 분석 할 수있는 JavaFX 응용 프로그램에서 작업하고 있습니다.스레드에서 진행률 표시 줄과 여러 레이블 업데이트

사용자 인터페이스를보기 좋게 만드는 것이 어렵지만 Swing을 사용하여이 작업을 수행했습니다. 따라서 JavaFX에서도 동일한 작업을 수행하려고합니다.

원래 Swing 앱에서 사용자가 선택한 폴더에서 파일 구문 분석을 시작하는 스레드를 만듭니다. 그것은 다음과 같이 작동

  1. 하는 구문 분석 할 파일의 총 수를 찾아 - 파일 수 및 폴더의 수는 지속적으로 UI
  2. 구문 분석에 두 개의 별도의 라벨에 표시되어있는 모든 파일을있는 것을 찾을 수를 MP3 파일을 저장하고 메타 데이터 저장 - 발견 된 MP3 파일의 수는 UI의 레이블에 계속 표시됩니다.

동시에 진행 상황을 보여주는 레이블이 업데이트되고 위의 두 단계의 진행. 첫 번째 단계의 진행률은 전체 진행률의 30 %를 차지하고 두 번째 단계는 나머지 70 %를 차지합니다.

작업을 진행률 막대에 바인딩하는 방법의 예가 있지만 상태, 파일 수, 폴더 수 및 MP3 수의 네 가지 레이블도 업데이트해야합니다.

updateMessage 레이블 중 하나를 처리 할 수 ​​있다고 생각하지만 다른 세 가지를 관리하는 방법을 모르겠습니다.

답변

8

여러 작업을 사용하여 문제를 비트로 분할합니다. 관리 작업을 사용하여 하위 작업의 상태 및 전반적인 진행 상태를 모니터링합니다. LinkedBlockingDeque과 같은 클래스를 사용하여 Task 실행, 시퀀싱 및 데이터 구조를 관리하십시오.

이 권장 솔루션은 문제에 대한 가장 간단한 해결책은 아니지만 제대로 수행되면 좋은 사용자 환경을 제공해야합니다.


나누기의 예

정복 접근은 다른 문제인가, 다음의 코드 샘플들을 참조 :

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

잠재적 간단한 다른 방법은 전체 프로세스에 대해 하나의 Task를 사용하고 필요에 따라 작업 코드에서 Platform.runLater를 호출하여 다시 자바 FX 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


더 많은 정보와 자바 FX의 동시성에 대한 추가 리소스에 대한 링크를 use of Platform.runLater and accessing the UI from a different thread for more information에 StackOverflow의 질문을 참조하십시오 .

+0

답변 해 주셔서 감사합니다. 이것을 시험하기 위해 시간이 좀 걸립니다. 이전에'Platform.runLater'를 사용해 본 경험이 없습니다. 스윙에서 나는'publishing() '을 사용하여 UI 요소의 수를 지속적으로 업데이트 할 수있는 SwingWorker를 사용했습니다. runLater는 비슷한 것을 제공합니까? – nivis

+0

나는'Platform.runLater'를 사용하여 스레드가 실행될 때 GUI 요소를 업데이트하는 방법에 대한 좋은 예를 찾고자했지만 아무 것도 찾지 못했습니다. 당신이 저에게 그런 예를 가르쳐 주시겠습니까, 아니면 어쩌면 그렇게 할 수있는 코드 샘플을 제공 할 수 있습니까? 내가 찾은 모든 예제는 스레드가 완료된 후 GUI를 업데이트합니다. – nivis

+0

요청 된 코드 샘플로 답변이 업데이트되었습니다. – jewelsea