12.5. Events and Event Handlers

In JavaFX, nodes can generate Event objects. This can happen automatically or in response to user input. Each event has a corresponding event handler, i.e., a method that is registered to handle the event when it is generated. Let’s add a button to ExampleApp, then register an event handler for one of the events the button might generate.

  1. In ExampleApp.java, import the Button class, then add the following line immediately after the line that creates the Text object:

    Button button = new Button("Click me!");
    

    This creates a Button object; however, it will NOT automatically appear in the app’s GUI!

  2. To add the Button object to the GUI, you need to add it to the scene. Here, we will add the button as a child of the HBox object already contained in the scene graph. This can be accomplished by adding the following line immediately after the line that adds the Text object to the HBox:

    root.getChildren().add(button);
    

    If you are adding multiple children to a node, you may prefer to use the variadic method addAll instead of add on the ObservableList<Node> returned by the getChildren method.

  3. Compile ExampleApp.java, then rerun ExampleDriver. You should now see the button!

    • Move your mouse over the button. You should notice that the styling of the button changes automatically as your mouse cursor enters and leaves the visual area of the button (the change is very subtle; look closely). Click on the button. Similarly, the styling of the button will change. As you interact with the button, you are actually causing the button to generate events! These events have default event handlers that cause the button’s style to change.

  4. When a user clicks on a button, that causes the button to generate an ActionEvent object. You can register an event handler for this event by calling the setOnAction method. Here is the signature of the setOnAction method:

    public final void setOnAction(EventHandler<ActionEvent> value)
    
  5. As you can see, to call the setOnAction method, we will need to supply a reference to an EventHandler<ActionEvent> object. It turns out that EventHandler<T> is an interface. This gives us many options. It also turns out that this interface is a functional interface, which means that we can use a lambda expression. We point out that EventHandler<T> is an interface before to remind you that you can always implement the interface in the usual way instead of using a lambda expression. Let’s create a handler that prints a message to standard output whenever the user clicks on the button.

    1. Let’s implement the EventHandler<ActionEvent> using a lambda expression. To do this, consult the API documentation for the interface and inspect its abstract handle method. The lambda expression will represent that method. Import the relevant types, then add the following line directly below the line where you created the button:

      EventHandler<ActionEvent> buttonHandler = event -> System.out.println("you clicked me!");
      
    2. The previous step only created the EventHandler<ActionEvent> object. Now we need to register it with the button using the setOnAction method. Add the following line directly below the line you added in the previous step:

      button.setOnAction(buttonHandler);
      
  6. Compile ExampleApp.java, then rerun ExampleDriver. Click on the button! If you followed the steps correctly, then you should see the text you clicked me! appear in your terminal window.

  7. Congratulations! You have successfully created your first interactive GUI app! The next step is to add more nodes/components to the scene graph, and then register event handlers that cause changes in those components instead of merely printing a message to standard output. This will be explored in the class exercises and some of your projects.