JavaFX时间轴完成后返回一个值

时间:2018-08-27 10:36:20

标签: java javafx timeline

我正在JavaFX中使用时间轴对Label进行倒计时:

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

我想在时间轴完成后返回一个值:

return true;

但是,似乎值会立即返回并且时间轴平行运行。如何等待时间轴完成其倒计时,然后返回值而不阻塞时间轴?

编辑:

为了更加清楚,我已经尝试过:

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 :(得分:4)

由于Timeline继承自Animation,因此您可以使用setOnFinished定义要在时间轴末尾执行的操作。

timeline.setCycleCount(6);
timeline.play();
timeline.setOnFinished(event -> countdownLabel.setText("COUNTDOWN FINISHED"));

答案 1 :(得分:1)

如果您真的想等到时间表完成,可以将CountDownLatchSemaphoresetOnFinished一起使用。像下面这样的东西应该起作用:

CountDownLatch latch = new CountDownLatch(1);
timeline.setCycleCount(6);
timeline.setOnFinished(event -> latch.countDown());
timeline.play();
latch.await();
return true;

答案 2 :(得分:1)

您正试图在一个线程中等待另一线程的工作结果。这就是创建synchronisation的目的!例如。 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 Application Thread”上运行此方法,因为它将阻止UI更新。在单独的线程上运行它:

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");
});

答案 3 :(得分:0)

除了拥有Animation的{​​{1}}之外,还要使用setOnFinished的{​​{1}}(KeyFramesetOnFinished) 。我修改了您的MCVE,以显示如何针对您的情况进行操作:

Timeline

在每个循环上,将执行Animation的{​​{1}},将计数减少1。当整个动画结束(所有周期)时,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变量来计算循环数,以便它们匹配。
  • 使用Java命名约定:标识符(名称)以小写字母开头。
  • 正确缩进代码,以便于阅读。