Возврат значения после завершения JavaFX Timeline - PullRequest
0 голосов
/ 27 августа 2018

Я использую временную шкалу в JavaFX для обратного отсчета Label:

timeline.setCycleCount(6);
timeline.play();

И я хочу вернуть значение после окончания временной шкалы:

return true;

Однако, похоже, что значение возвращается сразу, а временная шкала идет параллельно. Как я могу дождаться окончания обратного отсчета на временной шкале, а затем вернуть значение, не блокируя временную шкалу?

EDIT:

Чтобы было понятнее, я уже попробовал:

new Thread(() -> {
    timeline.play();
}).start();

while(!finished){ // finished is set to true, when the countdown is <=0

}
return true;

(Это решение не обновляет обратный отсчет.)

РЕДАКТИРОВАТЬ 2:

Вот минимальный, полный и проверяемый пример:

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;


public class CountdownTest extends Application {

    private Label CountdownLabel;
    private int Ctime;

    @Override
    public void start(Stage primaryStage) {

        CountdownLabel=new Label(Ctime+"");

        StackPane root = new StackPane();
        root.getChildren().add(CountdownLabel);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Countdown Test");
        primaryStage.setScene(scene);
        primaryStage.show();

        Ctime=5;

        if(myCountdown()){
            CountdownLabel.setText("COUNTDOWN FINISHED");
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    public boolean myCountdown(){
         final Timeline timeline = new Timeline(
                            new KeyFrame(
                                    Duration.millis(1000),
                                    event -> {
                                    CountdownLabel.setText(Ctime+"");
                                    Ctime--;

                                    }

                            )
                    );
         timeline.setCycleCount(6);
         timeline.play();
    return true;
    }

}

Вы можете видеть, что сначала отображается «COUNTDOWN FINISHED» и идет обратный отсчет до 0 вместо начала обратного отсчета и обратного отсчета до «COUNTDOWN FINISHED».

Ответы [ 4 ]

0 голосов
/ 28 августа 2018

Используйте Animation setOnFinished в дополнение к KeyFrame setOnFinished, которые у вас есть (Timeline - Animation). Iv'e изменил ваш MCVE, чтобы показать, как это сделать для вашего случая:

public class CountdownTest extends Application {

    private Label countdownLabel;
    private int ctime = 5;

    @Override
    public void start(Stage primaryStage) {
        countdownLabel = new Label();

        StackPane root = new StackPane();
        root.getChildren().add(countdownLabel);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Countdown Test");
        primaryStage.setScene(scene);
        primaryStage.show();

        myCountdown();
    }

    public void myCountdown() {
        final Timeline timeline = new Timeline(new KeyFrame(Duration.millis(1000),
            event -> {
                countdownLabel.setText(ctime + "");
                ctime--;
            }
        ));
        timeline.setCycleCount(ctime + 1);
        timeline.setOnFinished(e -> countdownLabel.setText("COUNTDOWN FINISHED"));
        timeline.play();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

В каждом цикле будут выполняться KeyFrame setOnFinished, уменьшая счет на 1. Когда закончится вся анимация (все ее циклы), будет Timeline setOnFinished. .

Примечания:

  • Используйте переменную ctime для вычисления количества циклов, чтобы они соответствовали.
  • Используйте соглашения об именах Java: идентификаторы (имена) начинаются со строчной буквы.
  • Правильный отступ вашего кода, чтобы его было легче читать.
0 голосов
/ 27 августа 2018

Если вы действительно хотите дождаться окончания временной шкалы, вы можете использовать CountDownLatch или Semaphore вместе с setOnFinished. Должно работать что-то вроде следующего:

CountDownLatch latch = new CountDownLatch(1);
timeline.setCycleCount(6);
timeline.setOnFinished(event -> latch.countDown());
timeline.play();
latch.await();
return true;
0 голосов
/ 27 августа 2018

Вы пытаетесь дождаться в одном потоке результата работы в другом потоке. Для этого была создана синхронизация ! Например. java.util.concurrent.Semaphore

public boolean waitForTimeline()  {
    Semaphore semaphore = new Semaphore(0);

    System.out.println("starting timeline");
    Timeline t = new Timeline();
    t.getKeyFrames().add(new KeyFrame(Duration.seconds(2)));
    t.setOnFinished((e)-> {
        System.out.println("releasing semaphore"); 
        semaphore.release();
    });
    t.play();

    System.out.println("waiting for timeline to end");
    try {
        semaphore.acquire();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
        return false;
    }
    return true;
}

Но учтите, что вы не можете запустить этот метод в «потоке приложений JavaFX», поскольку он будет блокировать обновления пользовательского интерфейса. Запустите его в отдельном потоке:

new Thread(()-> { 
    System.out.println("returned from timeline with " + waitForTimeline()); 
}).start();

или, лучше, вместо этого создайте слушателя с логикой, которую вы делаете после return, и вызовите этого слушателя из t.setOnFinished(). Для вашего примера это будет:

public void myCountdown(Runnable onSuccess){
    //...
    timeline.setOnFinished((e)-> {
        onSuccess.run();
    });
}

и соответствующий звонок:

myCountdown(()->{
    CountdownLabel.setText("COUNTDOWN FINISHED");
});
0 голосов
/ 27 августа 2018

Поскольку Timeline наследуется от Animation, вы можете использовать setOnFinished, чтобы определить действие, которое должно произойти в конце временной шкалы.

timeline.setCycleCount(6);
timeline.play();
timeline.setOnFinished(event -> countdownLabel.setText("COUNTDOWN FINISHED"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...