Events and Event Delegation Model

Introduction

In any interactive environment, the program should be able to respond to actions performed by the user. These actions can be a mouse click, key press, or selection of a menu item. The basis of event-driven programming is trying events to code that respond to those events. After working this far and grasping some of the fundamentals of object-oriented programming, it is possible to think that events will be handled using an object-oriented approach. Java's Abstract Windowing Toolkit (AWT) communicates these actions to the program using events. When the user initiates an action, the AWT generates an event and communicates it to event handlers. These event handlers can respond to the events appropriately.

The whole of event handling in Java AWT is done using two methods action() and the handleEvent() method. The action() method has three parameters, namely- the event that has occurred and the x and y coordinates at which this event occurred. To find out the AWT components like buttons, checkboxes, radio buttons, and text boxes in which the event was generated, the instanceof operator is used. The handleEvent() method is called automatically for an object, and an Event object is created and passed on to it.

What is Event Delegation Model in Java?

In the new event model, an event is propagated from a "source" object to a "Listener" object by invoking a method on the listener and passing in the instance of the event subclass that specifies the generated event type.. To say it in simple terms, when an event is fired, it is received by one or more listeners that act on that event. Every listener for an event is an instance of a class that implements a specific kind of listener interface.

Event types are encapsulated in a class hierarchy rooted at java.util.EventObject and one level below this is java.awt.AWTEvent package. Given below are some of the common terms related to event handling:

  • An object that implements a specific EventListener interface, which is an extension of the generic java.util.EventListener
  • An EventListener interface defines one or more methods that are to be invoked by the event source in response to each specific event type handled by the interface.
  • An item that generates or "fires" events is known as an event source. The source defines the set of events it emits by providing a set of set <EventType>Listener(for single cast) and add<EventType>Listener(for multicast) methods which are used to register specific listeners for those events.
  • An Adapter class includes all methods specified by the corresponding interface but not providing any functionality.

The event source in an AWT program is often a GUI component, and the listener is frequently an "adapter" object that implements the appropriate listener (or a set of listeners) so that an application can manage the flow/handling of events. Another AWT component that implements one or more listener interfaces could also be the listener object. A multicast approach for listeners is supported by all AWT event sources. As a result, different listeners can be added to and withdrawn from a single source. The sequence in which events are delivered to a group of registered listeners for a particular event on a given source is not guaranteed.

How we can Handle an Event?

The new model in the AWT's main design objectives are,

  • To make it simple and easy to learn.
  • To support a clear division of application code from GUI code.
  • To make it easier to write robust, error-resistant event handling code (strong compile-time checking).
  • To make it flexible enough to enable varied application models for event flow and propagation.
  • To support backward binary compatibility with the old model. 

A Java programmer has three options for handling an event,

  • Ignoring the event.
  • Handling of the event by the component where the event originated.
  • Delegating event handling to objects called listeners.

Whenever an AWT component wants to handle its own events, the component's subclass created has to do two things,

  • Enable receipt of events by calling enableEvents()
  • Provide a processActionEvent() method, which is called whenever the component is activated.

The delegation method is the best-suited method to handle events. It is not possible for a component to handle its events at all times. Hence this should be assigned to a different object called the listener. This process is called delegation. Each component class in the AWT has one addXXXListener() method for each event type that the component generates.

Types of Event Handling

 The AWT provides two conceptual types of events: low-level and semantic. An Event Listener interface typically has a separate method for each distinct event type the event class represents. It is also divided into low-level and semantic.

Low-Level Event

An event that represents a low-level input or window-system occurrence on a visual component on the screen is referred to as a low-level event. The following are the low-level event classes that AWT defines.

ComponentEvent (component resized, moved, etc.)

  • FocusEvent(component got focus, lost focus)
  • InputEvent
  • KeyEvent(component got key-press, key-release, etc.)
  • MouseEvent(component got mouse-down, mouse-move etc)
  • ContainerEvent
  • WindowEvent

The low-level event listener is as follows,

  • ComponentListener
  • ContainerListener
  • FocusListener
  • KeyListener
  • MouseListener
  • MouseMotionListener
  • WindowListener

Semantic Events

Semantic Events are defined at a higher level to encapsulate the semantics of a user interface component's model. The semantic event classes defined by the AWT are as follows:

  • ActionEvent(“do a command”)
  • AdjustmentEvent(“value was adjusted”)
  • ItemEvent(“item state has changed”)
  • TextEvent(“the value of the text object changed”)

The semantic listener is defined by the AWT as,

  • ActionListener
  • AdjustmentListener
  • ItemListener
  • TextListener

Mouse Events

These are generated whenever a mouse is moved, clicked, pressed, released, etc. The MouseEvent class represents these events as six constant values. This class has methods to get the coordinates at which a mouse event has occurred. The mouse move and mouse drag are treated differently from the other four types, namely, mouse pressed, mouse released, mouse entered, and mouse exited. Hence there are two types of mouse event listeners- MouseListener and MouseMotionListener.

The MouseListener interface has the following definitions.

public interface MouseListener {
    public void mouseClicked(MouseEvent e);
    public void mousePressed(MouseEvent e);
    public void mouseEntered(MouseEvent e);
    public void mouseExited(MouseEvent e);
    public void mouseReleased(MouseEvent e);
}

The MouseMotionListener interface has the following definition.

public interface MouseMotionListener {
  public void mouseDragged(MouseEvent e);
  public void mouseMoved(MouseEvent e);
}

An alternate way of handling mouse events is by letting components process their own ordinary mouse events using enableEvents(AWTEvent.MOUSE_EVENT_MAX) and processMouseEvent() methods.

The following illustrates the usage of mouse event listeners. Watch out for messages on the status line of the applet as and when there is a mouse event performed by the user. It also shows the coordinates at which such an event has occurred.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class MouseText extends Applet implements MouseListener, MouseMotionListener {
  public void init() {
    addMouseListener(this);
    addMouseMotionListener(this);
  }

  public void mouseClicked(MouseEvent e) {
    showStatus("Mouse clicked at " + e.getX() + "," + e.getY());
  }

  public void mouseEntered(MouseEvent e) {
    showStatus("Mouse entered at " + e.getX() + ", " + e.getY());
    for (int i = 0; i < 1000000; ++i);
  }

  public void mouseExited(MouseEvent e) {
    showStatus("Mouse Exited at " + e.getX() + "," + e.getY());
  }

  public void mousePressed(MouseEvent e) {
    showStatus("Mouse Pressed at " + e.getX() + "," + e.getY());
  }

  public void mouseDragged(MouseEvent e) {
    showStatus("Mouse Dragged at " + e.getX() + "," + e.getY());
  }

  public void mouseMoved(MouseEvent e) {
    showStatus("Mouse Moved at " + e.getX() + "," + e.getY());
  }
  public void mouseReleased(MouseEvent e) {}
}
/*
<applet code="MouseText.class" width=200 height=200>
</applet>
*/

Since this applet implements MouseListener and MouseMotionListener, it has to provide the functionality for all their methods. Observe that the mouseEntered() method has a small for loop. This is to ensure that the mouse-entered message remains on the status line for some time. Otherwise, it is not possible to see this very clearly. On executing this, the applet appears as below.

applet implements MouseListener and MouseMotionListener

Summary

When an event is fired, one or more listeners receive it and respond to it. Components can take care of events on their own or can assign that responsibility to objects known as listeners. An EventListener interface is typically represented by a separate method in an EventListener interface. MouseListener and MouseMotionListener are the two different categories of mouse event listeners.