дождитесь завершения задачи, не блокируя пользовательский интерфейс в javafx

Я пытаюсь создать приложение для викторины, используя JavaFX, поскольку я вызываю вопросы, используя

Q1.invoke();
Q2.invoke();

эти вопросы будут отображаться в потоке пользовательского интерфейса

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(); является блокирующим вызовом, он также блокирует поток пользовательского интерфейса, как этого добиться, не блокируя поток пользовательского интерфейса.


person Priyamal    schedule 25.10.2018    source источник


Ответы (2)


Не используйте для этой цели отдельный поток. Это только усложняет задачу. 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);
}

Вы можете легко реализовать тайм-аут или результат ответа на вопрос по-другому, например. задавая следующий вопрос или показывая результаты, когда последний вопрос сделан.

person fabian    schedule 25.10.2018

Для изменений в пользовательском интерфейсе вы должны использовать

Platform.runLater(() -> {

});

и для Thread вы должны использовать:

Task<Void> task = new Task<Void>() {
    @Override
    protected Void call() throws Exception {
                return null;
        }
};

и передать объект задачи в

executorService.submit(task)

надеюсь, это будет полезно

person Pervez    schedule 25.10.2018