여러 작업을 사용하여 문제를 비트로 분할합니다. 관리 작업을 사용하여 하위 작업의 상태 및 전반적인 진행 상태를 모니터링합니다. LinkedBlockingDeque과 같은 클래스를 사용하여 Task 실행, 시퀀싱 및 데이터 구조를 관리하십시오.
이 권장 솔루션은 문제에 대한 가장 간단한 해결책은 아니지만 제대로 수행되면 좋은 사용자 환경을 제공해야합니다.
나누기의 예
정복 접근은 다른 문제인가, 다음의 코드 샘플들을 참조 :
- splits a complex process into multiple managed subtasks한다.
- 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); }
}
더 많은 정보와 자바 FX의 동시성에 대한 추가 리소스에 대한 링크를 use of Platform.runLater and accessing the UI from a different thread for more information에 StackOverflow의 질문을 참조하십시오 .
답변 해 주셔서 감사합니다. 이것을 시험하기 위해 시간이 좀 걸립니다. 이전에'Platform.runLater'를 사용해 본 경험이 없습니다. 스윙에서 나는'publishing() '을 사용하여 UI 요소의 수를 지속적으로 업데이트 할 수있는 SwingWorker를 사용했습니다. runLater는 비슷한 것을 제공합니까? – nivis
나는'Platform.runLater'를 사용하여 스레드가 실행될 때 GUI 요소를 업데이트하는 방법에 대한 좋은 예를 찾고자했지만 아무 것도 찾지 못했습니다. 당신이 저에게 그런 예를 가르쳐 주시겠습니까, 아니면 어쩌면 그렇게 할 수있는 코드 샘플을 제공 할 수 있습니까? 내가 찾은 모든 예제는 스레드가 완료된 후 GUI를 업데이트합니다. – nivis
요청 된 코드 샘플로 답변이 업데이트되었습니다. – jewelsea