如何在 JavaFX 中重新启动计时器?

How to restart a timer in JavaFX?

我目前正在开发一个程序,用户可以在其中为不同的练习创建他们的时间间隔。一旦按下开始,第一个练习开始倒计时。完成后,会播放声音,第二个开始倒计时,依此类推,直到所有练习都完成并移除。我使用了一个计时器,它每 1 秒后将练习时间减去 1。问题是,我似乎无法在 java 中找到重新启动计时器的方法。完成所有练习后,我可以停止计时器,但当我想创建新练习并再次完成该过程时,我似乎找不到重新启动它的方法。我也找不到在特定过程中暂停并再次播放计时器的方法。我是 JavaFX 的新手,所以如果您能指导我如何更改代码以实现我正在寻找的目标,我将不胜感激。

Timer timer = new Timer();
startButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        //Timer task=new TimerTask();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                running=true;
                if (running==true)
                {
                    if (workoutsList.size() == 0) {
                        return;
                    }
                    if (workoutsList.size() == 1 && workoutsList.get(0).time == 1) {
                        text.setText("over!");
                        mediaPlayer1.play();
                        workoutsList.clear();
                        workouts.getItems().clear();
                        timer.cancel();
                        return;
                    }
                    workoutsList.get(0).time -= 1;
                    if (workoutsList.get(0).time == 0) {
                        workoutsList.remove(0);
                        mediaPlayer.play();
                        return;
                    }
                    workouts.getItems().clear();
                    workouts.refresh();
                    for (int i = 0; i < workoutsList.size(); i++) {
                        workouts.getItems().add(workoutsList.get(i));
                    }
                }
            }
        }, 0, 1000);
    }
});
stopButton.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        timer.cancel();
        running=false;
    }
});

因为 Timer 除了跟踪时间之外什么都不做,所以最好使用 javafx.animation API。这给了你一些优势:

  • 一切都发生在 JavaFX 应用程序线程,这意味着没有并发问题。
  • 您可以使用 AnimationcurrentTimecycleDuration 属性来跟踪倒计时中剩余的时间。
  • 您可以使用Animationplay()pause()stop()方法来控制定时器。
  • 您可以使用 AnimationonFinished 属性 在计时器结束时播放您的声音。

这是一个使用 PauseTransition 的示例,但您也可以使用例如Timeline.

import javafx.animation.Animation;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) {
    // javafx.util.Duration
    PauseTransition timer = new PauseTransition(Duration.minutes(5));
    // timer.setOnFinished(e -> /* play sound */);

    Button startBtn = new Button("Start");
    startBtn.setOnAction(e -> timer.play());

    Button pauseBtn = new Button("Pause");
    pauseBtn.setOnAction(e -> timer.pause());

    Button resetBtn = new Button("Reset");
    resetBtn.setOnAction(e -> timer.stop());

    Label label = new Label();
    label.setFont(Font.font("Monospaced", 20));
    label.textProperty().bind(timeLeftAsString(timer));

    HBox hbox = new HBox(10, startBtn, pauseBtn, resetBtn);
    hbox.setAlignment(Pos.CENTER);

    VBox root = new VBox(25, label, hbox);
    root.setPadding(new Insets(25));
    root.setAlignment(Pos.CENTER);

    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }

  private StringBinding timeLeftAsString(Animation animation) {
    return Bindings.createStringBinding(
        () -> {
          double currentTime = animation.getCurrentTime().toMillis();
          double totalTime = animation.getCycleDuration().toMillis();
          long remainingTime = Math.round(totalTime - currentTime);
          // java.time.Duration
          java.time.Duration dur = java.time.Duration.ofMillis(remainingTime);
          return String.format(
              "%02d:%02d:%03d", dur.toMinutes(), dur.toSecondsPart(), dur.toMillisPart());
        },
        animation.currentTimeProperty(),
        animation.cycleDurationProperty());
  }
}

旁注:您提到计时器完成时会播放声音,我可以看到对 mediaPlayer.play() 的调用。考虑到程序的性质,我假设正在播放的声音相对较短。如果是这种情况,您应该考虑使用 AudioClip 而不是 MediaPlayer.