Registering Handlers and Handling Events
Tags: java, programming, learning, beginners
Published: 2024-06-24 19:46:05

A handler is an object that must be registered with an event source object, and it must be an instance of an appropriate event-handling interface.

Java uses a delegation-based model for event handling: a source object fires an event, and an object interested in the event handles it. The latter object is called an _event handler_ or an event _listener_. For an object to be a handler for an event on a source object, two things are needed, as shown in Figure below.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejhp8w836sk7h1it290c.png)

1. _The handler object must be an instance of the corresponding event-handler_ interface to ensure that the handler has the correct method for processing the event. JavaFX defines a unified handler interface **EventHandler<T extends Event>** for an event **T**. The handler interface contains the **handle(T e)** method for processing the event. For example, the handler interface for **ActionEvent** is **EventHandler<ActionEvent>**; each handler for **ActionEvent** should implement the **handle(ActionEvent e)** method for processing an **ActionEvent**.
2. _The handler object must be registered by the source object._ Registration methods depend on the event type. For **ActionEvent**, the method is **setOnAction**. For a mouse pressed event, the method is **setOnMousePressed**. For a key pressed event, the method is **setOnKeyPressed**.

Let’s revisit [here](https://dev.to/paulike/event-driven-programming-2g88), HandleEvent.java. Since a **Button** object fires **ActionEvent**, a handler object for **ActionEvent** must be an instance of **EventHandler<ActionEvent>**, so the handler class implements EventHandler<ActionEvent> in line 34. The source object
invokes setOnAction(handler) to register a handler, as follows:

`Button btOK = new Button("OK"); // Line 17 in HandleEvent.java
OKHandlerClass handler1 = new OKHandlerClass(); // Line 19 in HandleEvent.java
btOK.setOnAction(handler1); // Line 20 in HandleEvent.java`

When you click the button, the **Button** object fires an **ActionEvent** and passes it to invoke the handler’s **handle(ActionEvent)** method to handle the event. The event object contains information pertinent to the event, which can be obtained using the methods. For example, you can use **e.getSource()** to obtain the source object that fired the event.

We now write a program that uses two buttons to control the size of a circle, as shown in Figure below. We will develop this program incrementally. First, we write the program in the program below that displays the user interface with a circle in the center (lines 16-20) and two buttons on the bottom (lines 22-28).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kr4i2j12np3jnwupjyuv.png)

```
package application;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ControlCircleWithoutEventHandling extends Application {
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		StackPane pane = new StackPane();
		Circle circle = new Circle(50);
		circle.setStroke(Color.BLACK);
		circle.setFill(Color.WHITE);
		pane.getChildren().add(circle);
		
		HBox hBox = new HBox();
		hBox.setSpacing(10);
		hBox.setAlignment(Pos.CENTER);
		Button btEnlarge = new Button("Enlarge");
		Button btShrink = new Button("Shrink");
		hBox.getChildren().add(btEnlarge);
		hBox.getChildren().add(btShrink);
		
		BorderPane borderPane = new BorderPane();
		borderPane.setCenter(pane);
		borderPane.setBottom(hBox);
		BorderPane.setAlignment(hBox, Pos.CENTER);
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(borderPane, 200, 150);
		primaryStage.setTitle("ControlCircle"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}
}

```

How do you use the buttons to enlarge or shrink the circle? When the _Enlarge_ button is clicked, you want the circle to be repainted with a larger radius. How can you accomplish this? You can expand and modify the program in the program above into one below with the following features:

1. Define a new class named **CirclePane** for displaying the circle in a pane (lines 65–81). This new class displays a circle and provides the **enlarge** and **shrink** methods for increasing and decreasing the radius of the circle (lines 74–76, 78–80). It is a good strategy to design a class to model a circle pane with supporting methods so that these related methods along with the circle are coupled in one object.
2. Create a **CirclePane** object and declare **circlePane** as a data field to reference this object (line 16) in the **ControlCircle** class. The methods in the **ControlCircle** class can now access the **CirclePane** object through this data field.
3. Define a handler class named **EnlargeHandler** that implements **EventHandler<ActionEvent>** (lines 50–55). To make the reference variable **circlePane** accessible from the **handle** method, define **EnlargeHandler** as an inner class of the **ControlCircle** class. (_Inner classes_ are defined inside another class. We use an inner class here and will introduce it fully in the next section.)
4. Register the handler for the _Enlarge_ button (line 30) and implement the **handle** method in **EnlargeHandler** to invoke **circlePane.enlarge()** (line 53).

```
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ControlCircle extends Application {
	private CirclePane circlePane = new CirclePane();
	
	@Override // Override the start method in the Application class
	public void start(Stage primaryStage) {
		// Hold two buttons in an HBox
		HBox hBox = new HBox();
		hBox.setSpacing(10);
		hBox.setAlignment(Pos.CENTER);
		Button btEnlarge = new Button("Enlarge");
		Button btShrink = new Button("Shrink");
		hBox.getChildren().add(btEnlarge);
		hBox.getChildren().add(btShrink);
		
		// Create and register the handler
		btEnlarge.setOnAction(new EnlargeHandler());
		btShrink.setOnAction(new ShrinkHandler());
		
		BorderPane borderPane = new BorderPane();
		borderPane.setCenter(circlePane);
		borderPane.setBottom(hBox);
		BorderPane.setAlignment(hBox, Pos.CENTER);
		
		// Create a scene and place it in the stage
		Scene scene = new Scene(borderPane, 200, 150);
		
		primaryStage.setTitle("ControlCircle"); // Set the stage title
		primaryStage.setScene(scene); // Place the scene in the stage
		primaryStage.show(); // Display the stage
	}
	
	public static void main(String[] args) {
		Application.launch(args);
	}
	
	class EnlargeHandler implements EventHandler<ActionEvent>{
		@Override // Override the handle method
		public void handle(ActionEvent e) {
			circlePane.enlarge();
		}
	}
	
	class ShrinkHandler implements EventHandler<ActionEvent>{
		@Override // Override the handle method
		public void handle(ActionEvent e) {
			circlePane.shrink();
		}
	}
}

class CirclePane extends StackPane{
	private Circle circle = new Circle(50);
	
	public CirclePane() {
		getChildren().add(circle);
		circle.setStroke(Color.BLACK);
		circle.setFill(Color.WHITE);
	}
	
	public void enlarge() {
		circle.setRadius(circle.getRadius() + 2);
	}
	
	public void shrink() {
		circle.setRadius(circle.getRadius() > 2 ? circle.getRadius() - 2 : circle.getRadius());
	}
}


```