Example app
Study session
Question objects, retries, Next and Restart.
Run this example
Stop the app and save your current Main and helpers outside src/. Copy the files shown below into the listed destinations in your standalone starter, creating resource folders when needed. Replace Main and the listed helpers. Keep the zero/ framework folder and build files. If an older downloaded kit does not have these examples, use the source shown here.
- examples/study/Main.java →
src/main/java/Main.java - examples/study/Question.java →
src/main/java/Question.java - examples/shared/ScoreDisplay.java →
src/main/java/ScoreDisplay.java
Run App to rebuild. These examples run in VS Code, in a separate JavaFX window.
Open related lessonRead the source
study/Main.java
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import zero.SimpleApp;
/** A small study session: Main owns the state and updates ordinary objects. */
public class Main extends SimpleApp {
private final Question[] questions = {
new Question("What is the value of 7 / 2 when both numbers are ints?", "3",
"Integer division drops the fractional part."),
new Question("What boolean value does 5 > 2 produce?", "true",
"A comparison produces true or false."),
new Question("What index selects the first element of a Java array?", "0",
"Java array indexes start at zero.")
};
private int questionIndex;
private int points;
private boolean answered;
private boolean finished;
private Label progress;
private Label question;
private TextField answer;
private Label feedback;
private Button check;
private Button next;
private Button restart;
private ScoreDisplay score;
@Override public void settings() {
title("Java study session");
size(580, 340);
}
@Override public void setup() {
progress = new Label();
question = new Label();
question.setWrapText(true);
answer = new TextField();
answer.setPromptText("Type your answer");
feedback = new Label();
feedback.setWrapText(true);
check = new Button("Check answer");
next = new Button("Next");
restart = new Button("Restart");
score = new ScoreDisplay();
check.setOnAction(event -> checkAnswer());
answer.setOnAction(event -> checkAnswer()); // Enter also checks the answer.
next.setOnAction(event -> nextQuestion());
restart.setOnAction(event -> restartSession());
HBox buttons = new HBox(12, check, next, restart);
VBox screen = new VBox(12, progress, question, answer, buttons, feedback, score.view());
screen.setPadding(new Insets(20));
show(screen);
restartSession();
}
private void checkAnswer() {
if (answered || finished) return;
Question current = questions[questionIndex];
if (current.accepts(answer.getText())) {
answered = true;
points++;
score.setScore(points);
feedback.setText("Correct! " + current.explanation());
answer.setDisable(true);
check.setDisable(true);
next.setDisable(false);
} else {
feedback.setText("Try again. You can retry without losing points.");
}
}
private void nextQuestion() {
if (!answered || finished) return;
if (questionIndex + 1 < questions.length) {
questionIndex++;
showQuestion();
} else {
finished = true;
progress.setText("Completed " + questions.length + " of " + questions.length);
question.setText("Study session complete!");
answer.clear();
answer.setDisable(true);
check.setDisable(true);
next.setDisable(true);
feedback.setText("You answered all " + questions.length + " questions correctly. "
+ "Final score: " + points + ". Choose Restart to practise again.");
}
}
private void showQuestion() {
answered = false;
progress.setText("Question " + (questionIndex + 1) + " of " + questions.length);
question.setText(questions[questionIndex].prompt());
answer.clear();
answer.setDisable(false);
feedback.setText("Enter an answer. Get it correct to unlock Next.");
check.setDisable(false);
next.setDisable(true);
restart.setDisable(false);
answer.requestFocus();
}
private void restartSession() {
questionIndex = 0;
points = 0;
finished = false;
score.setScore(points);
showQuestion();
}
public static void main(String[] args) { launch(args); }
}
study/Question.java
/** One ordinary object holds the data for one study question. */
public class Question {
private final String prompt;
private final String answer;
private final String explanation;
public Question(String prompt, String answer, String explanation) {
this.prompt = prompt;
this.answer = answer;
this.explanation = explanation;
}
public String prompt() { return prompt; }
public boolean accepts(String attempt) {
return answer.equalsIgnoreCase(attempt.trim());
}
public String explanation() { return explanation; }
}
shared/ScoreDisplay.java
import javafx.scene.Node;
import javafx.scene.control.Label;
/** An ordinary class: the app owns the number; this object displays it. */
public class ScoreDisplay {
private final Label label;
private final String caption;
public ScoreDisplay() {
this("Score");
}
public ScoreDisplay(String caption) {
this.caption = caption;
label = new Label(caption + ": 0");
}
public void setScore(int points) {
label.setText(caption + ": " + points);
}
public Node view() {
return label;
}
}