0

I am building an application which is an exam. All the questions are shown on different screens, all with a progressbar showing how much time the user has left. When the progressbar is full, the screen with another question is shown and the progressbar and timeline should be resetted.

When the time is up, the next screen is shown and the timeline resets, but the progressbar (shown in code as 'PRGB') remains full and it will not reset to an empty progressbar. This is my code:

public void timeBar() throws Exception{
    Timeline timeline = new Timeline(
            new KeyFrame(Duration.ONE, new KeyValue(PRGB.progressProperty(), 0)),
            new KeyFrame(Duration.seconds(Main.time), e-> {
            }, new KeyValue(PRGB.progressProperty(), 1))
    );
    timeline.setCycleCount(1);
    timeline.play();
    timeline.setOnFinished(event -> {
        Main.setPane(questionNumber);
        questionNumber++;
        timeline.play();
        //in here the progressbar has to be resetted
    });
}

Update: I have deleted my ProgressBar from SceneBuilder, and made a new one on which I then run the code below (with a few alterations taking by your suggestions). But now the progressbar does reset it self, but it does not show the progress: it stays empty.

public void timeBar() throws Exception{
    Timeline timeline = new Timeline(
            //I only use two keyframes instead of three
            new KeyFrame(Duration.seconds(Main.time), e-> {
            }, new KeyValue(PRGB.progressProperty(), 1))
    );
    timeline.setCycleCount(1);
    timeline.play();
    timeline.setOnFinished(event -> {
        Main.setPane(questionNumber);
        questionNumber++;
        //The setProgress is added
        PRGB.setProgress(0.0F);
        timeline.play();
    });
}
yoliska
  • 1
  • 2
  • I cannot reproduce this issue. I'm not sure why you use `Duration.ONE` instead of `Duration.ZERO`, but when I test the code it properly resets the progress bar when a new question is displayed. (It may be convenient to move the code for switching the questions to a event handler of the first `KeyFrame` btw...) – fabian Jun 22 '18 at 16:58
  • I'm not sure either, I copied the code from another question on here. But I moved the code, it looks better that way, thank you! But I still can't get the progressbar to reset, did you use the code from the question? – yoliska Jun 23 '18 at 10:53

2 Answers2

1

This can probably be done better. In this example, 3 seconds is given for each question with 1 second at the end of each question to load the next question. Code from here.

import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.KeyFrame;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application
{

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

    @Override
    public void start(Stage stage)
    {
        Label lblCurrentQuestion = new Label();
        ProgressBar prgb = new ProgressBar(0);

        int numberOfQuestions = 5;//Number of questions
        int timeForEachQuestion = 3;//3 second to do each questions
        AtomicInteger currentProgressCounter = new AtomicInteger(0);
        AtomicInteger currentQuestionCounter = new AtomicInteger(1);

        Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), (event) -> {
            if (currentProgressCounter.get() == timeForEachQuestion + 1) {
                //Go to next question!
                prgb.setProgress(0);
                currentProgressCounter.set(0);
                currentQuestionCounter.incrementAndGet();
            }
            lblCurrentQuestion.setText("Question " + currentQuestionCounter.get());
            prgb.setProgress(currentProgressCounter.getAndIncrement() / (double) timeForEachQuestion);
        }));

        fiveSecondsWonder.setCycleCount(numberOfQuestions * (timeForEachQuestion + 1));
        fiveSecondsWonder.play();
        fiveSecondsWonder.setOnFinished(event -> {
            PauseTransition wait = new PauseTransition(Duration.seconds(1));
            wait.setOnFinished((e) -> {
                /*YOUR METHOD*/
                lblCurrentQuestion.setText("Quiz done!");
                prgb.setProgress(0);
                wait.playFromStart();
            });
            wait.play();
        });

        Scene scene = new Scene(new StackPane(new VBox(lblCurrentQuestion, prgb)), 500, 500);

        stage.setScene(scene);
        stage.show();
    }
}
SedJ601
  • 12,173
  • 3
  • 41
  • 59
  • Why change to a progress bar that jumps every second? Why use `AtomicInteger` when you could just replace the lambda with an anonymus class that contains primitive fields? – fabian Jun 22 '18 at 17:03
  • I didn't think this one through. That is why I lead with `This can probably be done better` – SedJ601 Jun 22 '18 at 17:15
  • I am a beginner to JavaFX, so I don't quite understand the code, I barely understand the code from my question. But I tried to implement the code, using my own variables (and I am using SceneBuilder so I used the code without the stage), but it still does not reset the progressbar.. – yoliska Jun 23 '18 at 10:54
0

You have a call to timeline.play() in your setOnFinished() call. Remove that call so that the progress bar doesn't get reset to full.

Also, you should reset your progress bar by doing progressBar.setProgress(0.0F); in the setOnFinished()

Blake Ordway
  • 308
  • 1
  • 8