JavaFX Running a large amount of countdown timers at once?

前端 未结 4 1209
面向向阳花
面向向阳花 2021-01-28 10:04

So I can see a couple different ways to do what I need and I\'ve done a bunch of google/stack overflow searching but can\'t find really what I\'m looking for. I need to run mult

4条回答
  •  萌比男神i
    2021-01-28 10:31

    So the 1st question I have is. Since this "tab" is running on a separate controller but is included into the main program, does it run on a separate application thread?

    No, there can only be one JavaFX Application instance per JVM, and also one JavaFX Application Thread per JVM.

    As for how you could update the timer, it is fine to use Timeline - one for each timer. Timeline does not run on separate thread - it is triggered by the underlying "scene graph rendering pulse" which is responsible for updating the JavaFX GUI periodically. Having more Timeline instances basically just means that there are more listeners that subscribes to the "pulse" event.

    public class TimerController {
        private final Timeline timer;
    
        private final ObjectProperty timeLeft;
    
        @FXML private Label timeLabel;
    
        public TimerController() {
            timer = new Timeline();
            timer.getKeyFrames().add(new KeyFrame(Duration.seconds(1), ae -> updateTimer()));
            timer.setCycleCount(Timeline.INDEFINITE);
    
            timeLeft = new SimpleObjectProperty<>();
        }
        public void initialize() {
            timeLabel.textProperty().bind(Bindings.createStringBinding(() -> getTimeStringFromDuration(timeLeft.get()), timeLeft));
        }
    
        @FXML
        private void startTimer(ActionEvent ae) {
            timeLeft.set(Duration.ofMinutes(5)); // For example timer of 5 minutes
            timer.playFromStart();
        }
    
        private void updateTimer() {
            timeLeft.set(timeLeft.get().minusSeconds(1));
        }
    
        private static String getTimeStringFromDuration(Duration duration) {
            // Do the conversion here...
        }
    }
    

    Of course, you can also use Executor and other threading methods, provided you update the Label via Platform.runLater(). Alternatively, you could use a Task.

    This is a general example when using background thread:

    final Duration countdownDuration = Duration.ofSeconds(5);
    Thread timer = new Thread(() -> {
        LocalTime start = LocalTime.now();
        LocalTime current = LocalTime.now();
        LocalTime end = start.plus(countDownDuration);
    
        while (end.isAfter(current)) {
            current = LocalTime.now();
            final Duration elapsed = Duration.between(current, end);
    
            Platform.runLater(() -> timeLeft.set(current)); // As the label is bound to timeLeft, this line must be inside Platform.runLater()
            Thread.sleep(1000);
        }
    });
    

提交回复
热议问题