I try to build a countdown timer for home workout, which runs down the same interval twice and then gives you an extra interval break. After that it should start over again with the 3 intervals.
Currently I am successfully running the first interval from thirty seconds down to zero. My problem is, that I can not determine whether the JavaFX Task is completed or not. More precisely I cannot start over with it again WITHOUT creating several self overwriting process (e.g. with a for loop).
This is my Controller.class for handling my FXML file:
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Slider;
public class Controller {
private int time;
@FXML
private Label counterLabel;
private static StringProperty displayTime = new SimpleStringProperty("30");
@FXML
private Button startstop;
@FXML
private ProgressIndicator progress;
private static DoubleProperty prog = new SimpleDoubleProperty(0.0);
@FXML
private Slider Pausendauer; // pause length
@FXML
private Slider Trainingsdauer; //interval length
@FXML
private Slider Repeats;
public void initialize() {
progress.setProgress(0);
counterLabel.textProperty().bind(displayTime);
progress.progressProperty().bind(prog);
}
public void click(ActionEvent e) throws InterruptedException {
//event for clicking start button
//Task for Counting (Should be repeatable after running through
time = (int)Trainingsdauer.getValue();
Task<String> count = new TaskTimer(time);
displayTime.bind(count.valueProperty());
prog.bind(count.progressProperty());
count.run();
}
}
And that is my Task (Timer) class:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.concurrent.Task;
public class TaskTimer extends Task<String>{
private int time;
double fraction;
double prog;
public static void main(String[] args) {
}
public TaskTimer(int sec) {
this.time = sec;
this.fraction = 1.0 / time; //claculating for closng circle
this.prog = 0.0;
}
protected String call() throws Exception {
// TODO Auto-generated method stub
//runs scheduled without delay
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable(){
public void run() {
time = time - 1; //Decrement of time
prog = prog + fraction; //increase progress
updateProgress(prog, 1);
if(time >= 10) { // Makes 01 from 1 and so on
updateValue(time+"");
}else {
updateValue("0"+time);
}
System.out.println(time+"");
if (time <= 0) {
updateProgress(1, 1);
scheduler.shutdown();
}
}
}, 1, 1, TimeUnit.SECONDS);
return time+"";
}
}
And that's the application at work (the sad one it iteration it's capable of):
GUI Design to describe function

What can I try next? Have tried a whole bunch of things right now. Most of my "solutions" ended up with self overwriting twins and or a freezing UI.
You can use the Task.setOnSucceeded method to construct and invoke a new Task as demonstrated in the following mre:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class RestartProgressIndicator extends Application {
private static int COUNT_DOWN = 10;
@Override
public void start(Stage stage) {
Work work = new Work();
Button button = new Button("Go");
button.setDefaultButton(true);
button.setOnAction(e -> {
work.work(COUNT_DOWN);
button.setDisable(true);
});
Pane root = new BorderPane(null,work.getPane(),null, button,null);
root.setPadding(new Insets(20.));
Scene scene = new Scene(root, Color.WHITE);
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class Work{
private TaskTimer count;
private final ProgressIndicator pi;
private final Pane pane;
private int counter = 0;
Work(){
pi = new ProgressIndicator();
pi.setMinWidth(150); pi.setMinHeight(150);
pane = new Pane(pi);
}
void work(int seconds){
count = new TaskTimer(seconds);
pi.progressProperty().bind(count.progressProperty());
count.setOnSucceeded(e->{
pi.progressProperty().unbind();
if(isRestarart()) {
work(seconds);
}
});
Thread th = new Thread(count);
th.setDaemon(true);
th.start();
}
private boolean isRestarart() {
// TODO apply restart logic
return ++counter < 3;
}
Pane getPane() {
return pane;
}
}
class TaskTimer extends Task<String>{
private final int seconds;
double fraction, prog;
public TaskTimer(int seconds) {
this.seconds = seconds;
fraction = 1.0 / seconds;
prog = 0.0;
}
@Override
protected String call() throws Exception {
int time = seconds;
while(true){
time = time - 1; //Decrement of time
prog = prog + fraction; //increase progress
updateProgress(prog, 1);
if(time >= 10) { // Makes 01 from 1 and so on
updateValue(time+"");
}else {
updateValue("0"+time);
}
TimeUnit.SECONDS.sleep(1);
if (time <= 0) {
updateProgress(1, 1);
break;
}
};
return time+"";
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With