gpt4 book ai didi

JavaFX 启动屏幕消息和进度未更新

转载 作者:行者123 更新时间:2023-12-02 04:35:12 24 4
gpt4 key购买 nike

我有一个 JavaFX 应用程序,用于在启动时检查数据库是否存在。如果未找到数据库,则必须先创建“种子”数据库,然后程序才能继续。

由于创建种子数据库可能很长,因此我想显示启动屏幕并随着过程的进行显示进度更新。只有种子数据库完全写入后,程序才能继续。

这是启动屏幕的类:

public final class SplashWindow {

private final Label message;
private final ProgressBar progress;
private final Stage splashStage;

public SplashWindow() {
Image img = new Image(IMAGE_PREFIX + "splash_image.png");
double imgWidth = img.getWidth();
ImageView splashImage = new ImageView(img);
splashImage.setFitWidth(imgWidth);
splashImage.setPreserveRatio(true);

message = new Label("Saving seed database...");
message.setPrefWidth(imgWidth);
message.setAlignment(Pos.CENTER);

progress = new ProgressBar();
progress.setPrefWidth(imgWidth);

Pane splashVBox = new VBox(3);
splashVBox.setPadding(new Insets(5));
splashVBox.getChildren().addAll(splashImage, progress, message);

splashStage = new Stage(StageStyle.UTILITY);
splashStage.setScene(new Scene(splashVBox));
}

public void bindMessageProperty(ReadOnlyStringProperty sp) {
message.textProperty().bind(sp);
}

public void bindProgressProperty(ReadOnlyDoubleProperty dp) {
progress.progressProperty().bind(dp);
}

public void show() {
splashStage.show();
}

public void shutdown() {
message.textProperty().unbind();
progress.progressProperty().unbind();
splashStage.hide();
}
}

运行时,初始屏幕会正确显示图像、进度条和文本消息区域。

SplashWindow 类通过以下方法调用:

private void saveSeedDatabase(ObservableList<RefModel> docList) {
SplashWindow splash = new SplashWindow();

Task<Integer> saveTask = new Task<Integer>() {
@Override
protected Integer call() throws InterruptedException {
updateMessage("Saving references...");
int docsSaved = 0;
for (RefModel rm : docList) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}

updateMessage("Saving: " + rm.getTitle());
saveNewReference(rm);
docsSaved++;
updateProgress(docsSaved, docList.size());
}
updateMessage("Saved " + docsSaved + " references to database");
return docsSaved;
}
};
saveTask.setOnSucceeded((WorkerStateEvent t) -> {
splash.shutdown();
});

splash.bindMessageProperty(saveTask.messageProperty());
splash.bindProgressProperty(saveTask.progressProperty());
splash.show();

new Thread(saveTask).start();
try {
saveTask.get();
} catch (InterruptedException | ExecutionException ex) {
// Do nothing
}
}

运行时,会显示初始屏幕,但不会显示更新消息和进度。当鼠标悬停在启动屏幕上时,它会显示等待光标。

如果方法末尾的 try/catch block 被注释掉,则主程序将尝试继续执行而不等待数据库写入。在这种情况下,启动屏幕被主程序窗口隐藏,但在运行时显示更新消息。从调试来看,一切似乎都在正确的线程上运行——数据库的东西在工作线程上,SplashWindow 的东西在 FX 事件线程上。

很明显,对 saveTask.get() 的调用正在阻塞 UI 线程,但我不确定为什么。

@JewelSea写了nice alternative这不太适合我的程序架构。改变我的程序以使用他的解决方案并非不可能。

但是,我不明白为什么 get() 调用会阻止 UI。我做错了什么。

最佳答案

根据JavaDocs :

(get()) Waits if necessary for the computation to complete, and then retrieves its result.

在不阻塞 GUI 线程的情况下检索计算值可以使用 getValue() 来完成。 。但是:当 Task 成功完成其工作时,此方法仅返回结果。这就是为什么您应该在 onSucceeded 中执行此 aysnc block 。

关于JavaFX 启动屏幕消息和进度未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30917285/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com