如何正确地关闭javafx Alerts / fileChooser等 [英] How to properly thread off javafx Alerts/fileChooser etc
问题描述
我正在查看这个问题线程任务完成后JavaFX显示对话已完成,但我的问题恰恰相反。在文件追踪器或警报之后,如果您需要从用户那里获得一些数据,最好的方法是什么?
I was looking at this question JavaFX show dialogue after thread task is completed, but my question is kind of the opposite. What is the best way to thread off after a filechooser or alert where you need some data back from the user?
这就是我现在所拥有的:
Here's what I have now:
Platform.runLater(()->{
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if(file == null) {
return;
}
executorService.execute(()->{
//more code here which uses file
});
});
其中executorService是先前创建的ExecutorService。我想我可以轻松地使用任务或线程或其他任何东西,但它如何被线程化无关紧要,只是因为它需要一段时间,我不希望在应用程序线程上发生它,因为它会锁定UI。
where executorService is an ExecutorService that was made earlier. I suppose I could just as easily use a Task or a Thread or anything else, but how it's threaded off doesn't matter, just that it's something that takes a while that I don't want to have happen on the Application thread because it would lock up the UI.
我知道这不是一个mvce,但我希望它能说明我在 Platform.runLater $中的线程所遇到的问题c $ c>来电。
I know this isn't an mvce, but I hope it demonstrates the problem I'm having with threads inside Platform.runLater
calls.
这是一个极端的例子,说明这种事情有多复杂
Here's an extreme example of how convoluted this kind of thing gets
@FXML
public void copyFiles(ActionEvent event){
//this method is on the application thread because a button or something started it
// so we thread off here
executorService.execute(()->{
// do some stuff
// ...
// get location to copy to from user
// must happen on the application thread!
Platform.runLater(()->{
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if(file == null) {
return;
}
executorService.execute(()->{
// more code here which uses file
// ...
// oh wait, some files have the same names!
// we need a user's confirmation before proceeding
Platform.runLater(()->{
Alert alert = new Alert(AlertType.CONFIRMATION, "Do you want to overwrite files with the same names?", ButtonType.OK, ButtonType.CANCEL);
Optional<ButtonType> choice = alert.showAndWait();
if(choice.isPresent && choice.get == ButtonType.OK){
// do something, but not on the application thread
executorService.execute(()->{
// do the last of the copying
// ...
});
}
});
});
});
});
}
推荐答案
看来你的问题是需要的在后台任务中间的信息,只能在JavaFX Application线程上检索。 James_D给出的答案使用 FutureTask
。我想提供一个替代方案: CompletableFuture
(在Java 8中添加)。
It seems your issue is needing information in the middle of a background task that can only be retrieved while on the JavaFX Application thread. The answer given by James_D works perfectly for this using FutureTask
. I'd like to offer an alternative: CompletableFuture
(added in Java 8).
public void copyFiles(ActionEvent event) {
executorService.execute(() -> {
// This uses CompletableFuture.supplyAsync(Supplier, Executor)
// need file from user
File file = CompletableFuture.supplyAsync(() -> {
// show FileChooser dialog and return result
}, Platform::runLater).join(); // runs on FX thread and waits for result
if (file == null) {
return;
}
// do some stuff
// ask for confirmation
boolean confirmed = CompletableFuture.supplyAsync(() -> {
// show alert and return result
}, Platform::runLater).join(); // again, runs on FX thread and waits for result
if (confirmed) {
// do more stuff
}
});
}
两者 FutureTask
和 CompletableFuture
将适合您。我更喜欢 CompletableFuture
,因为它提供了更多选项(如果需要),并且 join()
方法不会检查像 get()
这样的例外。但是, CompletableFuture
是 Future
(就像 FutureTask
)所以你仍然可以使用 get()
一个 CompletableFuture
。
Both FutureTask
and CompletableFuture
will work for you. I prefer CompletableFuture
because it it provides more options (if needed) and the join()
method doesn't throw checked exceptions like get()
does. However, CompletableFuture
is a Future
(just like FutureTask
) and so you can still use get()
with a CompletableFuture
.
这篇关于如何正确地关闭javafx Alerts / fileChooser等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!