CS 346 (W23)
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Events

JavaFX expands on the Listener model that was introduce in Java Swing, and provides support for a wide varieties of events. The Event class is the base class for a JavaFX event. Common events include:

  • MouseEvent − This is an input event that occurs when a mouse is clicked. It includes actions like mouse clicked, mouse pressed, mouse released, mouse moved.
  • KeyEvent − This is an input event that indicates the key stroke occurred over a node. This event includes actions like key pressed, key released and key typed.
  • WindowEvent − This is an event related to window showing/hiding actions. It includes actions like window hiding, window shown.

These events are generated automatically by the appropriate source (e.g. pressing a key when the cursor is in a TextField widget will generate a KeyPress event).

Event Handling is the mechanism that controls the event and decides what should happen, if an event occurs. JavaFX provides handlers and filters to handle events. In JavaFX every event has:

  • Target − The node on which an event occurred. A target can be a window, scene, or a node.
  • Source − The source from which the event is generated. In the above scenario, mouse is the source of the event.
  • Type − Type of the occurred event.

Assume that we have an application which has a Circle, Stop and Play Buttons1. If you click on the play button, the source will be the mouse, the target node will be the play button and the type of the event generated is the mouse click.

Sample Application

Whenever an event is generated, JavaFX walks through the following phases.

1. Route Construction

The default/initial route of the event is determined by construction of an Event Dispatch chain. It is the path from the stage to the source Node. In the example above, the dispatch chain would be from Stage -> Scene -> Grop -> Play Button.

Play Button

2. Event Capturing Phase (filters)

After the construction of the event dispatch chain, the root node of the application dispatches the event. This event travels to all nodes in the dispatch chain (from top to bottom). If any of these nodes has a filter registered for the generated event, it will be executed. If none of the nodes in the dispatch chain has a filter for the event generated, then it is passed to the target node and finally the target node processes the event.

3. Event Bubbling Phase (handlers)

In the event bubbling phase, the event is travelled from the target node to the stage node (bottom to top). If any of the nodes in the event dispatch chain has a handler registered for the generated event, it will be executed. If none of these nodes have handlers to handle the event, then the event reaches the root node and finally the process will be completed.

4. Event Handlers and Filters

Event filters and handlers are classes which can process an event. A node can register to more than one handler/filter (e.g. for handling events from different targets). Handlers or filters setup on a parent node can be created to process events for their children.

To add or remove filters or handlers, you need to use the appropirate method on a node.

Example: Mouse Event Filter

// Creating the mouse event handler 
EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() { 
   @Override 
   public void handle(MouseEvent e) { 
      System.out.println("Hello World"); 
      circle.setFill(Color.DARKSLATEBLUE);  
   } 
};   
// Adding event Filter 
Circle.addEventFilter(MouseEvent.MOUSE_CLICKED, eventHandler);

// Remove like this
// circle.removeEventFilter(MouseEvent.MOUSE_CLICKED, eventHandler);

Example: Mouse Event Handler

// Creating the mouse event handler 
EventHandler<javafx.scene.input.MouseEvent> eventHandler = 
   new EventHandler<javafx.scene.input.MouseEvent>() { 
   
   @Override 
   public void handle(javafx.scene.input.MouseEvent e) { 
      System.out.println("Hello World"); 
      circle.setFill(Color.DARKSLATEBLUE);             
   } 
};    
// Adding the event handler 
circle.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, eventHandler);

// Remove like this
// circle.removeEventHandler(MouseEvent.MOUSE_CLICKED, eventHandler);

Nodes also have convenience methods for adding handlers directly, without defining them ahead of time. It’s common practice to combine these with lambdas for much more concise event handling code.

For example, the Circle class in the example above has the following convenience methods, which accept specific types of handlers:

Using these methods, we can replace the Event Handler code above with convenience methods and a lambda:

// Convenience method to add mouse event handler as a lambda
circle.setOnMouseClicked(event -> {
   System.out.println("Hello World"); 
   circle.setFill(Color.DARKSLATEBLUE);  
});

This is considered “standard practice”.

Handling Common Events

Nodes have convenience methods for handling common event types. They include:

  • setOnMouseClicked()
  • setOnMousePressed()
  • setOnMouseReleased()
  • setOnMouseMoved()
  • setOnKeyPressed()
  • setOnKeyReleased()

Additionally, there is a generic “action” handler which responds to the standard interaction with a control e.g. pressing a button, or selecting a menu item.

For example, here’s a handler for a “save” button (from sample-code/desktop/contacts)

val save = Button("Save")

save.setOnAction { event ->
	model.add(Contact(name.text, phone.text, email.text))
  model.save()
}

  1. Example taken from https://www.tutorialspoint.com/javafx/javafx_event_handling.htm, which has a full walkthrough. ↩︎