我有一個JavaFX應用程序在啓動時檢查是否存在數據庫。如果未找到數據庫,則必須在程序可以繼續之前創建「種子」數據庫。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塊被註釋掉,主程序將嘗試繼續而不等待數據庫被寫入。在這種情況下,啓動畫面被主程序窗口隱藏,但它在工作時會顯示更新消息。從調試它,它看起來像一切正在正確的線程上運行 - 數據庫的東西在工作線程上,SplashWindow
材料是在FX事件線程。
看起來很清楚,saveTask.get()
的調用阻塞了UI線程,但我不知道爲什麼。
@JewelSea寫了一個nice alternative,它不適合我的程序架構。改變我的計劃以使用他的解決方案並不是不可能的。
但是,我不明白爲什麼get()
調用阻止用戶界面。我究竟做錯了什麼。
另請參閱http://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests/30250308#30250308 –
@James_D:本週早些時候閱讀。非常好。感謝您的支持。 – clartaq