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, andtimeline.play()to start or resume.
Watch out for:
- The
fx:idlblCountdownmust match the@FXMLfield name, andhandleStartmust 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 aKeyFrameits 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
donechanges.
Watch out for:
- The
fx:idpbProgressmust match the@FXMLfield name exactly, or the screen will not load. - The value runs from
0.0to1.0, not0to100. A value of50shows as a full bar, not half. - Use
(double) done / totalso the division is done with decimals. Without the cast,done / totalis integer division and gives0untildonereachestotal. - Setting the value to
-1puts 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.