Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX启动屏幕消息和进度未更新_Java_Multithreading_Javafx - Fatal编程技术网

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

JavaFX启动屏幕消息和进度未更新,java,multithreading,javafx,Java,Multithreading,Javafx,我有一个JavaFX应用程序,它在启动时检查数据库是否存在。如果找不到数据库,则必须先创建“种子”数据库,然后程序才能继续 由于创建种子数据库可能会很长时间,因此我希望显示一个启动屏幕,并在进程进行时显示进度更新。只有在种子数据库完全写入之后,程序才能继续 以下是启动屏幕的类: public final class SplashWindow { private final Label message; private final ProgressBar progress;

我有一个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
    }
}
private void saveSeedDatabase(可观察列表docList){
SplashWindow splash=新的SplashWindow();
Task saveTask=新任务(){
@凌驾
受保护的整数调用()引发InterruptedException{
更新消息(“保存引用…”);
int docsSaved=0;
用于(参考型号rm:docList){
如果(isCancelled()){
更新消息(“已取消”);
打破
}
updateMessage(“保存:+rm.getTitle());
saveNewReference(rm);
docsSaved++;
updateProgress(docsSaved,docList.size());
}
updateMessage(“保存的”+文档保存的+“对数据库的引用”);
返回已保存的文档;
}
};
saveTask.setOnSucceeded((WorkerStateEvent t)->{
splash.shutdown();
});
splash.bindMessageProperty(saveTask.messageProperty());
splash.bindProgressProperty(saveTask.progressProperty());
splash.show();
新线程(saveTask.start();
试一试{
saveTask.get();
}捕获(InterruptedException | ExecutionException ex){
//无所事事
}
}
运行时,会显示启动屏幕,但不会显示更新消息和进度。当鼠标悬停在启动屏幕上时,将显示等待光标

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

显然,调用
saveTask.get()
会阻塞UI线程,但我不确定原因

已经编写了一个不太适合我的程序架构的。要改变我的计划以配合他的解决方案并非不可能

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

根据:

get()
)在必要时等待计算完成,然后检索其结果


在不阻塞GUI线程的情况下检索计算出的值将使用。但是:此方法仅在
任务
成功完成其工作时返回结果。这就是为什么你应该在街区里做这件事。

另请看@James\u D:本周早些时候的文章。很不错的。谢谢你的支持。不,使用
getValue()
方法仍然可以让程序在写入数据库之前继续运行。我想阻止
saveSeedDatabase()
方法返回,直到任务完成并写入数据库,但不冻结对初始屏幕的更新。关键是您在FX应用程序线程上调用
saveSeedDatabase
(您必须这样做,因为它创建并显示了一个
阶段
)。因此,如果您在该方法中阻塞(“在任务完成之前阻止该方法返回”),则必然会阻塞FX应用程序线程。任务完成后需要执行的任何操作都必须在
onSucceeded
处理程序中完成。