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.
- 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 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; each handler for ActionEvent should implement the handle(ActionEvent e) method for processing an ActionEvent.
- 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, HandleEvent.java. Since a Button object fires ActionEvent, a handler object for ActionEvent must be an instance of EventHandler, so the handler class implements EventHandler 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).
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:
- 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.
- 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.
- Define a handler class named EnlargeHandler that implements EventHandler (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.)
- 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());
}
}
Top comments (0)