Time, progress, and animation

IA tooling, not an exam topic. These are JavaFX patterns to adapt for your IA. Nothing here is examinable, and your IA must be your own work.

This page covers two time-related needs: doing something on a repeating beat, and showing how far along a task is.

New here? Read Start here: how every recipe fits together first; it explains the two places you edit and the fx:id link every recipe relies on.


Do something on a repeating beat

What this does: runs a piece of code on a fixed beat, for example once a second. This is the engine behind a countdown timer or a clock.

When you would use it in your IA: a countdown for a quiz or game, a clock that updates every second, or a status line that refreshes on a regular tick.

In SceneBuilder (the layout): add a Label to show the count (fx:id lblCountdown) and a button to start it (onAction handleStart). The timeline itself is created in code.

<Label fx:id="lblCountdown" text="60" />
<Button text="Start" onAction="#handleStart" />

In the controller (the .java file):

Imports:

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
import javafx.fxml.FXML;
import javafx.scene.control.Label;

Controller:

@FXML private Label lblCountdown;

private int secondsLeft = 60;
private Timeline timeline;

@FXML
public void initialize() {
    // One KeyFrame that fires every second and calls tick().
    timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> tick()));
    timeline.setCycleCount(Animation.INDEFINITE);   // keep repeating
    lblCountdown.setText(String.valueOf(secondsLeft));
}

@FXML
private void handleStart() {
    timeline.play();
}

private void tick() {
    // your IA logic here: what should happen on each beat
    secondsLeft--;
    lblCountdown.setText(String.valueOf(secondsLeft));
    if (secondsLeft <= 0) {
        timeline.stop();
    }
}

Where your own logic goes: inside tick(), marked // your IA logic here. That body is what happens on every beat. Building and starting the timeline is reusable wiring.

Make it your own:

  • Change Duration.seconds(1) to set the beat. Duration.millis(500) fires twice a second.
  • Put whatever should happen each beat inside tick().
  • Call timeline.stop() when you are done, and timeline.play() to start or resume.

Watch out for:

  • The fx:id lblCountdown must match the @FXML field name, and handleStart must exist in the controller, or the screen will not load.
  • setCycleCount(Animation.INDEFINITE) is what makes it repeat. Without it, the beat fires once and stops.
  • The event -> tick() part is a lambda, which is outside the exam-style Java subset but is the standard way to give a KeyFrame its action.
  • Remember to stop the timeline when the screen closes or the count reaches zero, or it keeps running in the background.

Mix with: Show progress toward a goal, Tell the user something.


Show progress toward a goal

What this does: fills a bar to show how far along a task is, from empty to full.

When you would use it in your IA: progress through a multi-step form, how many questions of a quiz are done, or how full a booking is against its capacity. Any “x out of y” you want to show visually.

In SceneBuilder (the layout): add a ProgressBar and give it an fx:id of pbProgress. Nothing else to add here.

<ProgressBar fx:id="pbProgress" progress="0" />

In the controller (the .java file):

Imports:

import javafx.fxml.FXML;
import javafx.scene.control.ProgressBar;

Controller:

@FXML private ProgressBar pbProgress;

private void showProgress(int done, int total) {
    // setProgress takes a value from 0.0 (empty) to 1.0 (full).
    pbProgress.setProgress((double) done / total);
}

Where your own logic goes: call showProgress(done, total) from your own code with your running count and target:

// your IA logic here: work out done and total from your data
showProgress(answered, questionCount);

Make it your own:

  • Call showProgress(done, total) with your own running count and target.
  • The bar is driven by your data, so update it whenever done changes.

Watch out for:

  • The fx:id pbProgress must match the @FXML field name exactly, or the screen will not load.
  • The value runs from 0.0 to 1.0, not 0 to 100. A value of 50 shows as a full bar, not half.
  • Use (double) done / total so the division is done with decimals. Without the cast, done / total is integer division and gives 0 until done reaches total.
  • Setting the value to -1 puts the bar in its “unknown” animated state, useful when you cannot measure how much is left.

Mix with: Do something on a repeating beat, Keep the UI responsive during slow work, Update a chart when the data changes.


© EduCS.me — A resource hub for Computer Science education

This site uses Just the Docs, a documentation theme for Jekyll.