1

My Programm needs nine Countdowntimers. The timers are started by the user. In my implementation I create a timerclasses for each timer started. The timerclass uses a timeline. Depending on the start of the timers the seconds are asynchrone.

I am not sure how to proceed.

My first thought were to use only 1 timeline for all countdowns. I would put all stringProperties into a list and the timeline will change the property. I am not so sure if this is a good way?

With some google I found out that there is animationtimer which could be used for such a problem. But I couldn't understand the examples. I have to overwrite the handle method. How should I update my timer with this?

Androz2091
  • 2,931
  • 1
  • 9
  • 26
Moone
  • 38
  • 5
  • If you are using `JavaFX`, have a look at the [`Animation`](https://docs.oracle.com/javase/8/javafx/api/javafx/animation/Animation.html) API. Also, look at this question. -> https://stackoverflow.com/questions/9966136/javafx-periodic-background-task. Specifically [`Timeline`](https://docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html) – SedJ601 Jan 10 '20 at 15:30

1 Answers1

2

The idea is correct: use one animation tool such as PauseTransition or TimeLine (1) to update all counters as demonstrated in the following MRE:

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class SyncedCounters extends Application {

    private static final int MAX_COUNT = 100;
    private Map<Label, Integer> counters;
    private VBox countersPane;

    @Override public void start(Stage stage) throws IOException {

        counters = new HashMap<>();
        countersPane = new VBox();
        Button addCounter = new Button("Add Counter");
        addCounter.setOnAction(e->addCounter());
        BorderPane root = new BorderPane(countersPane, null, null, null, addCounter);
        stage.setScene(new Scene(new ScrollPane(root),250,200));
        stage.show();
        update();
    }

    private void update() {

        PauseTransition pause = new PauseTransition(Duration.seconds(1));
        pause.setOnFinished(event ->{
            updateCounters();
            pause.play();
        });
        pause.play();
    }

    private void addCounter() {

        Label label = new Label(String.valueOf(MAX_COUNT));
        label.setAlignment(Pos.CENTER);
        label.setPrefSize(150, 25);
        counters.put(label, MAX_COUNT);
        countersPane.getChildren().add(label);
    }


    private void updateCounters() {
        for(Label l : counters.keySet()){
            int counterValue = counters.get(l);
            if(counterValue > 0 ){
                counterValue--;
                l.setText(String.valueOf(counterValue));
                counters.put(l, counterValue);
            }
        }
    }

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

enter image description here


(1) To use TimeLine instead of PauseTransition change update() to :
void update() {

    Timeline timeline = new Timeline();
    timeline.setCycleCount(Animation.INDEFINITE);

    KeyFrame keyFrame = new KeyFrame(
            Duration.seconds(1),
            event -> {updateCounters();}
    );

    timeline.stop();
    timeline.getKeyFrames().clear();
    timeline.getKeyFrames().add(keyFrame);
    timeline.play();
}
c0der
  • 18,467
  • 6
  • 33
  • 65