问题描述
我制作了一个小型的MVC程序,该程序将文件从A复制到B。为了更好地显示进度,我使用ProgressBar
和Observer Pattern
进行刷新。
模型(复印机和可观察的):
[...]
Files.copy(file.toPath(), Paths.get(destinationPath.toString() + "/" + file.getName()),
StandardCopyOption.REPLACE_EXISTING);
copyingFile = file.getName();
progress++;
setChanged();
notifyObservers("progress");
[...]
和视图(ProgressBar +观察者):
[...]
progressBar = new ProgressBar();
[...]
@Override
public void update(Observable observable, Object arg) {
if (observable != null && observable instanceof MainModel) {
if (arg instanceof String && "progress".equals(arg)) {
Platform.runLater(() -> {
progressBar.setProgress(model.getProgress());
copyingFile.setText(model.getCopyingFile());
percent.setText(df.format(progressBar.getProgress()* 100) + "%");
});
}
[...]
这很好。
ProgressBar
会不断更新,但是如果我复制100多个文件(大约2MB),它将不再起作用。
似乎notifyObservers("progress")
触发频繁并被卡住,或者某些东西或线程太忙于复制文件,而应该更新ProgressBar
的JavaFX Thread却没有时间做它的工作。
整个问题使我想到了代码,并且我怀疑这种用观察者模式快速更新ProgressBar
方法似乎不是一个好方法。
更新ProgressBar
的正确方法是什么?
绑定属性?
另一个问题:我正在使用观察者模式来更新视图中的所有数据。 因为模型必须更新很多不同的东西,并且它并不总是需要更新整个数据,所以我使用这种更新方式:
@Override
public void update(Observable observable, Object arg) {
if (observable != null && observable instanceof MainModel) {
if (arg instanceof String && "progress".equals(arg)) {
Platform.runLater(() -> {
progressBar.setProgress(model.getProgress());
copyingFile.setText(model.getCopyingFile());
percent.setText(df.format(progressBar.getProgress() * 100) + "%");
if (progressBar.getProgress() > 0.5) {
percent.setTextFill(Color.WHITE);
}
});
} else if (arg instanceof String && "finished".equals(arg)) {
Platform.runLater(() -> {
progressBar.setProgress(1);
copyingFile.setText("Fertig!");
percent.setText("100%");
finishButton.setDisable(false);
});
} else if (arg instanceof String && "events".equals(arg)) {
eventChoiceBox.setDisable(false);
List<String> events = new LinkedList<>();
events.addAll(model.getEvents());
Collections.sort(events);
events.add(0, "Neue Veranstaltung...");
eventChoiceBox.setItems(FXCollections.observableArrayList(events));
eventChoiceBox.getSelectionModel().select(model.getEvent());
} else {
userNames.setItems(FXCollections.observableArrayList(model.getUsers()));
filesList.setItems(FXCollections.observableArrayList(model.getFilesAsString()));
userNames.getSelectionModel().select(model.getUser());
}
}
我对整个if-else
事物和关键字(进度,完成,事件)的这种方式感到怀疑。
好吧,它大多数时候都可以使用这种方式工作,但这是否是一种好方法?
非常感谢你!
1楼
我怀疑您的问题是由于您传递给progressBar.setProgress
的值所致。
该值必须介于0.0到1.0之间,但看起来您可能正在传递复制的文件数。
实现观察者模式的方法有很多,它们实际上并不使用Observable和Observer类。
尤其是JavaFX,使用可观察的,可绑定的属性。
您的progress
变量可以替换为 ,其可观察的progressProperty可以绑定到ProgressBar的值。
它也可以绑定到百分比指示器,并且任务的message属性可以绑定到当前文件指示器:
Task<?> copyTask = new Task<Void>() {
@Override
protected Void call()
throws IOException {
int progress = 0;
for (File file : files) {
Files.copy(file.toPath(), Paths.get(destinationPath.toString(), file.getName()),
StandardCopyOption.REPLACE_EXISTING);
updateMessage(file.getName());
updateProgress(++progress, files.size());
}
return null;
}
};
ReadOnlyDoubleProperty taskProgress = copyTask.progressProperty();
progressBar.progressProperty().bind(taskProgress);
finishButton.disableProperty().bind(taskProgress.lessThan(1.0));
percent.textProperty().bind(
taskProgress.multiply(100).asString("%.0f%%"));
Paint defaultColor = new Label().getTextFill();
Paint halfDoneColor = Color.WHITE;
percent.textFillProperty().bind(
Bindings.when(taskProgress.greaterThan(0.5)).then(halfDoneColor).otherwise(defaultColor));
copyingFile.textProperty().bind(copyTask.messageProperty());
new Thread(copyTask).start();