How events are handled in a hierarchy of components

Download the code

The example below shows how a component can choose to handle an event send to it, or, by default, pass it to its parent in the container hierarchy. The program is a standalone, whose top-level component is the container type Frame (a window with a title bar). The frame contains a Panel, which is invisible, and the panel contains a Button.

The button is implemented in a class MyButton, so that the default event handler, the method handleEvent, can be overridden to show its behavior. It traps a button push with an Event whose id is ACTION_EVENT. Note that it does not trap the MOUSE_DOWN event even though a button push involves a MOUSE_DOWN action. This is determined by the Peer subsystem that links the Java button to the underlying windowing system of the particular platform you are working on. When the button traps the push event, it toggles a switch and chooses either to return true or false depending on the state of the toggle switch. Returning true tells the system that the event has been handled, and that is the end of it. However, if handleEvent returns false, then the system passes the event on the component's parent. In this case it is the panel, whose default handleEvent method (inherited from component) merely returns false, so that its parent, the frame, gets the event.

The frame is implemented in a class called ShowEvents. Again, the handleEvent method is overridden, and it traps several kinds of mouse event, and the action event passed from the button (or any other component that it contains). The trace shows that when the button's handleEvent returns true, the frame does not receive the event, but when the button's handleEvent returns false, then it does.

import java.awt.*;

class ShowEvents extends Frame {
  String eventType = " ";
  MyButton button = new MyButton(this, "Press");
  Panel panel = new Panel();
  
  public ShowEvents(int WidthInPixels, int heightInPixels) {
    setTitle( "Show Events" );
    resize( WidthInPixels, heightInPixels );
    add(panel);
    panel.add(button);
  }

  public boolean handleEvent(Event userAction) {
    if (userAction.id == Event.WINDOW_DESTROY) {
      displayMessage("WINDOW_DESTROY");
      System.exit(0);
    }
    else if (userAction.id == Event.MOUSE_DOWN)
      displayMessage( "MOUSE_DOWN" );
    else if (userAction.id == Event.MOUSE_ENTER)
      displayMessage( "MOUSE_ENTER" );
    else if (userAction.id == Event.MOUSE_EXIT)
      displayMessage( "MOUSE_EXIT" );
    else if (userAction.id == Event.MOUSE_DRAG)
      displayMessage( "MOUSE_DRAG" );
    else if (userAction.id == Event.ACTION_EVENT)
      displayMessage("ACTION_EVENT");
    return super.handleEvent(userAction);
  }

  public void displayMessage(String message) {
    System.out.println(message);
    eventType = message;
    repaint(); // redraw the window
  }

  public void paint(Graphics display) {
    button.resize(100, 50);
    button.move(100, 100);
    display.drawString(eventType, 30, 40);
  }

  public static void main(String args[]) {
    ShowEvents mainWindow = new ShowEvents(300, 200);
    mainWindow.show();
  }
}
 
class MyButton extends Button {
  boolean toggle = true;
  ShowEvents frame;
  
  MyButton(ShowEvents c, String text) {
    super(text);
    frame = c;
  }

  public boolean handleEvent(Event userAction) {
    if (userAction.id == Event.ACTION_EVENT) {
      frame.displayMessage("Button ACTION_EVENT");
      if (toggle)
        toggle = false;
      else
        toggle = true;
      return toggle;
    }
    else if (userAction.id == Event.MOUSE_DOWN)
      frame.displayMessage("Button MOUSE_DOWN");
    return super.handleEvent(userAction);
  }
}