java - 等待任务完成而不阻塞 javafx 中的 UI
问题描述
我正在尝试使用 JavaFX 创建一个测验应用程序,因为我正在使用
Q1.invoke();
Q2.invoke();
这些问题将显示在 UI 线程上
public void display(McqQuestion mcqQuestion) {
resourceAsStream = getClass().getResourceAsStream("/mcqview.fxml");
fxmlLoader = new FXMLLoader();
if (executorService==null) executorService =Executors.newSingleThreadExecutor();
Parent root = null;
try {
root = fxmlLoader.load(resourceAsStream);
Mcqview controller = fxmlLoader.getController();
controller.setAnswer1(mcqQuestion.getAnswers().get(0));
//controller class has setters to accept question properties.
controller.multipleChoiceQuestionType = this;
this.view.getBorderPane().setCenter(root);
}
一旦问题显示出来,我需要等到我得到答案,如果我没有得到答案,应该调用下一个问题。所以我在显示方法中引入了一个线程来等待超时
submit = executorService.submit(() -> {
try {
TimeUnit.SECONDS.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
try {
submit.get(20,TimeUnit.SECONDS);
System.out.println("waiting finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
由于这future.get();
是一个阻塞调用,它也阻塞了 UI 线程,如何在不阻塞 UI 线程的情况下实现这一点。
解决方案
不要为此目的使用单独的线程。这只会让事情变得更难。JavaFX 提供了不需要您为并发问题而烦恼的等待方式。
在这种情况下,等待可以通过PauseTransition
一个onFinished
处理程序来完成。处理来自用户输入的事件处理程序的答案。
private static class Question {
private final String questionText;
private final String answers[];
private final int correctAnswerIndex;
public Question(String questionText, String[] answers, int correctAnswerIndex) {
if (answers.length != 3) {
// for simplicity's sake allow only exactly 3 answers
throw new IllegalArgumentException();
}
this.questionText = questionText;
this.answers = answers;
this.correctAnswerIndex = correctAnswerIndex;
}
}
private VBox questionPane;
private Label questionText;
private Button[] answerButtons;
private PauseTransition pauseTransition;
private Question currentQuestion;
private void answer(int index) {
pauseTransition.stop(); // no longer wait for timeout
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setContentText((index == currentQuestion.correctAnswerIndex)
? "correct answer"
: "incorrect answer");
// show result and exit
alert.showAndWait();
Platform.exit();
}
private void ask(Question question) {
questionText.setText(question.questionText);
for (int i = 0; i < 3; i++) {
answerButtons[i].setText(question.answers[i]);
}
currentQuestion = question;
pauseTransition.playFromStart(); // start timeout timer
}
private void timeout() {
pauseTransition.stop();
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setContentText("your time ran out");
// cannot use showAndWait form animation directly
Platform.runLater(() -> {
// show result and exit
alert.showAndWait();
Platform.exit();
});
}
@Override
public void start(Stage stage) {
pauseTransition = new PauseTransition(Duration.seconds(10));
pauseTransition.setOnFinished(evt -> timeout());
questionText = new Label();
questionText.setWrapText(true);
questionPane = new VBox(questionText);
questionPane.setPrefSize(400, 400);
answerButtons = new Button[3];
for (int i = 0; i < 3; i++) {
final int answerIndex = i;
Button button = new Button();
button.setOnAction(evt -> answer(answerIndex));
answerButtons[i] = button;
questionPane.getChildren().add(button);
}
Scene scene = new Scene(questionPane);
stage.setScene(scene);
stage.show();
Question question = new Question(
"What is the answer to the ultimate question of life, the universe, and everything?",
new String[]{"Mew", "42", "Peanut butter"},
1
);
ask(question);
}
您可以轻松实现超时或以不同方式回答问题的结果,例如通过询问下一个问题或在完成最后一个问题时显示结果。
推荐阅读
- python - Pandas:将带有 if/else 条件的 for 循环转换为 apply 方法(lambda 函数)
- javascript - 简单 5 色 - 选择器,获取表单中文本的十六进制值
- javascript - 使用 WebSockets 在 Lua 和 NodeJS 之间进行通信不起作用
- java - 猜谜游戏逻辑(二分查找)
- javascript - Javascript 颜色选择器。如何在不导致浏览器崩溃的情况下显示所有 255x255x255 RGB 值?
- ios - xcode 无法预览新的 SwiftUI 项目
- javascript - java脚本箭头函数
- google-apps-script - Google App Script 根据相对于每个 cellRange 的 1 个单元格引用为多个 cellRange 提供相同的条件格式
- html - 如何使用 VBA 访问 Web?请检查我的代码
- linux - 创建默认内核头文件 (C)