Java Arena
Step 1 of 5

Buttons that do something

The windows of module 48 looked right, but their buttons did nothing when clicked. This module makes windows react: a click runs code that you write, and so can typing. As in module 48, each click or bit of typing on this page runs your program again from the start, with everything you did before it, and the code is ordinary JavaFX code.

An event handler

When the user clicks a button, JavaFX makes an event: an object that describes what happened. It hands the event to the button's event handler, if the button has one. A handler is given to a button with setOnAction. A town's drawbridge gets a control panel:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) {
        Label status = new Label("The bridge is down.");
        Button raise = new Button("Raise the bridge");
        raise.setOnAction(event -> status.setText("The bridge is up."));

        stage.setScene(new Scene(new VBox(status, raise)));
        stage.setTitle("Drawbridge");
        stage.show();
    }

    public static void main(String[] args) {
        launch(Main.class);
    }
}
The window

After: Click "Raise the bridge"

This window is wider than the screen: scroll it sideways, or read it as text below.

The window as text
Window "Drawbridge"
  VBox
    Label "The bridge is up."
    Button "Raise the bridge"

The window is drawn as it is after the clicks listed with it: here, one click on the button.

  • setOnAction takes an EventHandler<ActionEvent>. EventHandler is an interface of JavaFX with one method, handle, and a click on a button is an ActionEvent, so here the method is void handle(ActionEvent event). An interface with one method can be implemented with a lambda (module 37), so the handler here is event -> status.setText("The bridge is up."): the lambda's body is what handle does.
  • The parameter event is the ActionEvent. This handler doesn't need it, but it must be there, since handle has that parameter. The name is yours to choose; e is common too.
  • Writing a lambda needs no import for EventHandler or ActionEvent: Java works out the lambda's type from setOnAction.
  • start runs once and builds the window. The line with setOnAction doesn't change the label: it only gives the button its handler, and the handler's code runs later, each time the button is clicked.
  • The lambda uses status, a variable of start. Step 2 looks at which variables a lambda can use.

A handler runs at every click

The front desk of a hotel gets a bell. Its handler prints, and so does start:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) {
        Button bell = new Button("Ring the bell");
        bell.setOnAction(event -> System.out.println("Ding!"));

        stage.setScene(new Scene(new VBox(bell)));
        stage.setTitle("Front desk");
        stage.show();
        System.out.println("start is done");
    }

    public static void main(String[] args) {
        launch(Main.class);
    }
}
The window

After: Click "Ring the bell", then click "Ring the bell"

This window is wider than the screen: scroll it sideways, or read it as text below.

The window as text
Window "Front desk"
  VBox
    Button "Ring the bell"
Output
start is done
Ding!
Ding!

start is done comes first: start sets up the window and returns. Only then can the user click, and each click runs the handler once more.

Reading a text field in a handler

A handler can use the other parts of the window: read a text field, set a label. A converter for a kitchen timer turns seconds into minutes:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) {
        TextField seconds = new TextField();
        seconds.setPromptText("Seconds");
        Button convert = new Button("Convert");
        Label result = new Label("");
        convert.setOnAction(event -> {
            int total = Integer.valueOf(seconds.getText());
            result.setText(total / 60 + " min " + total % 60 + " s");
        });

        stage.setScene(new Scene(new VBox(8, seconds, convert, result)));
        stage.setTitle("Timer");
        stage.show();
    }

    public static void main(String[] args) {
        launch(Main.class);
    }
}
The window

After: Type "135" in text field 1, then click "Convert"

This window is wider than the screen: scroll it sideways, or read it as text below.

The window as text
Window "Timer"
  VBox spacing 8
    TextField "135", prompt "Seconds"
    Button "Convert"
    Label "2 min 15 s"
  • A handler of several statements has its body in braces, as a lambda in module 37 can.
  • seconds.getText() runs when the button is clicked, so it reads what the user has typed by then. Type another number and click again, and the handler reads the new one.
  • With the field empty, Integer.valueOf("") throws a NumberFormatException. An exception in a handler doesn't end the program: JavaFX prints it (Exception in thread "JavaFX Application Thread" and the stack trace), and the window stays open for the next click. The checks in this module always type a number before they click.

Clicking from code

A program can click its own buttons: button.fire() runs the button's handler, as a click does. Some programs in this module use it, so that you can see what their handlers do without clicking.

Your task

Challenge 1 of 3

A study room has a screen by its door. Fill in the three blanks, so that Book changes the label to Room 4 is booked and Leave changes it back to Room 4 is free. The task card shows the window after a click on Book.

Challenge 2

A club votes by a show of hands, and its secretary tries out a window for counting them. The program clicks its own buttons with fire(). What does it print?

Challenge 3

A children's party hands out candy. The window is built already: a text field for the number of candies (the prompt text Candies), one for the number of children (Children), the buttons Share and Clear, and an empty label. Give the buttons their handlers:

  • Share reads both numbers and sets the label to how many candies each child gets and how many are left over, like Each child gets 7, and 3 are left over for 45 candies and 6 children.
  • Clear empties both text fields and the label. clear() empties a text field.

The checks always type whole numbers, and at least 1 child, before they click Share. The task card shows the window after typing 45 and 6 and clicking Share.