Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

Event Handling in JDK 1.0.2, The handleEvent() Method

Java Programming, Lecture Notes # 64, Revised 8/3/97.

Note: Because the event model for JDK 1.0 is rapidly becoming obsolete, material on the JDK 1.0 event model will not be covered in classroom lectures or examinations in Professor Baldwin's CIS 2103K (Intermediate Java Programming) classes at Austin Community College.


Introduction

To the best of my ability, the material in this lesson conforms to the Java API Documentation 1.0.2. It does not conform to JDK 1.1 which is in beta evaluation at the time of this writing (February 1997). Sun has announced that it will contain important changes to the Abstract Windows Toolkit, including changes to the implementation of events and event handling.

When JDK 1.1 is released and hard information regarding those changes becomes available, this lesson will be supplemented with a new lesson describing events and event handling under JDK 1.1.

As described in a previous lesson, whenever the operating system (OS) sends a message to the Java runtime system as a result of user activity (which I shall start referring to as user events or simply events), the runtime system

(Things are actually a little more complicated than this, with the involvement of a method named postEvent(). However, as a practical matter, this description should suffice.)

The handleEvent() method can either "handle" the event and return true or "not handle" the event and return false. If these true/false rules aren't carefully adhered to, the result will be unpredictable but probably not good.

If handleEvent() returns false, the runtime system still needs to get the event handled. If the object involved in the user event is contained within another object, the runtime system will call the handleEvent() method of that container object passing it the Event object as a parameter.

This process will continue until the event either gets handled or there are no more container objects to pass it up to, at which time the runtime system will apply default processing to the event. Default processing probably means that it will simply be ignored.

This lesson discusses the use of handleEvent() to respond to user input in a GUI system.

The handleEvent() Method

The handleEvent() method is an instance member of the java.awt.Component class. Its signature follows: You can override handleEvent() in your program to handle the events that your program is interested in.

If you override handleEvent() in your program, unless you handle all possible events (which is not very likely), you should call the handleEvent() method of the superclass to handle those events not handled by your program before returning to the Java runtime system.

Default Behavior

According to Using Java, Special Edition, Second Edition by Joseph Weber, et al. the default behavior of handleEvent() is defined by the following code. This code is more enlightening than the information in the API Documentation in this particular instance, so I decided to use it instead of the information from the API Documentation. (I hope that it is correct.)

The default behavior of handleEvent() (as indicated by the following code) is to

If no match is found, handleEvent() returns false signaling to the Java runtime system that the event was not properly handled.

Note that in two different cases in the switch statement in the code, either of two different id values end up calling the same event handler. Those cases are highlighted in boldface.

These predefined event handler methods are simply convenience methods which do nothing in their default state but return false. They are meant to be overridden as a more-convenient way to deal with certain types of events. We can override them if we want to, but that is a subject for another lesson.

Note that there are about fourteen other id values defined as symbolic constants in the Event class which are not tested in the default version of handleEvent().


/*File Event01.txt
This is Listing 19-12 from Using Java, Special Edition
by Joseph Weber, et al.
*/
public boolean handleEvent(Event evt) { 
  switch (evt.id) { 
    case Event.MOUSE_ENTER: return mouseEnter(evt, evt.x, evt.y); 
    case Event.MOUSE_EXIT: return mouseExit(evt, evt.x, evt.y); 
    case Event.MOUSE_MOVE: return mouseMove(evt, evt.x, evt.y); 
    case Event.MOUSE_DOWN: return mouseDown(evt, evt.x, evt.y); 
    case Event.MOUSE_DRAG: return mouseDrag(evt, evt.x, evt.y); 
    case Event.MOUSE_UP: return mouseUp(evt, evt.x, evt.y); 
    case Event.KEY_PRESS: 
    case Event.KEY_ACTION: return keyDown(evt, evt.key); 
    case Event.KEY_RELEASE: 
    case Event.KEY_ACTION_RELEASE: return keyUp(evt, evt.key); 

    case Event.ACTION_EVENT: return action(evt, evt.arg); 
    case Event.GOT_FOCUS: return gotFocus(evt, evt.arg); 
    case Event.LOST_FOCUS: return lostFocus(evt, evt.arg); 
  } //end switch
  return false; 
}

Sample Event-Handling Program

The following program is about the simplest event-handling program that I was able to create. It doesn't do very much, but it does illustrate some important points.

To teach it effectively, we will either need to have some screen shots on overhead transparencies, or be able to display it running in the class. The second approach would be the most effective one.

I purposely avoided the use of the convenience methods in this case and overrode handleEvent() to deal with all of the events of interest.

How it Operates

The program creates a small window on the screen. If you point to a spot inside the window and click the left mouse button, the program displays the coordinates of the mouse pointer at the time of, and in the location of the click. This is accomplished by responding to MOUSE_DOWN events.

If you click on a spot outside the window, the program ignores it altogether.

The program also responds to WINDOW_DESTROY events. This is the type of event that occurs when you close a window by clicking on the X-button in the upper right-hand corner of the window, or by double-clicking on the control box in the upper left-hand corner of the window.

Because this is our first event-handling program, we will discuss it in some detail. However, the discussion will concentrate on the event-related code rather than the GUI-related code.


/*File Event01.java Copyright 1997, R.G.Baldwin
Illustrates a very simple event handler that overrides
the handleEvent() method and displays the coordinates of 
mouse clicks in a window.

Also responds to WINDOW_DESTROY to terminate the program
when the user clicks the close box.
*/

import java.awt.*;

//Make the controlling class extend the Frame class
// to produce a graphic window and a subclass of Component.
public class Event01 extends Frame{
  String msg = ""; //save message for display here
  int clickX = 0, clickY = 0;//save coordinates for display here

  //Create and size the window
  public static void main(String[] args){
    Event01 displayWindow = new Event01(); //instantiate obj of this type
    displayWindow.resize(300,200);//set window size
    displayWindow.setTitle("Copyright 1997, R.G.Baldwin");
    displayWindow.show();//display the window
  }//end main

  //General purpose event handler overrides 
  // handleEvent() method in Component class
  // In all cases, use the super keyword to
  // call the handleEvent() method in the
  // Component class to handle events 
  // not being handled here before returning
  // to Java runtime system.
  public boolean handleEvent(Event evntObj){
    switch(evntObj.id){//determine the type of event
      case Event.MOUSE_DOWN : myMousDwnEvntHandler(evntObj.x, evntObj.y);
                              break;
      case Event.WINDOW_DESTROY : System.exit(0);
    }//end switch
    return super.handleEvent(evntObj);                      
  }//end handleEvent()
  
  //This method is dispatched from handleEvent() to handle
  // a MOUSE_DOWN event.  It could just as well have been
  // coded directly inside the switch statement in handleEvent()
  public void myMousDwnEvntHandler(int x, int y){
    clickX = x; //save mouse coordinates
    clickY = y;
    msg = "" + x + ", " + y; //construct message for display
    repaint(); //force a repaint of the window
  }//end myMousDwnEvntHandler()
  
  //Override paint method to repaint the window
  public void paint(Graphics g){
    g.drawString(msg, clickX, clickY);
  }//end paint()
  
}//end class Event01

We Need a Subclass of Component

To begin with, in order to be able to process events, we need an object that is derived from the Component class. We accomplish this by causing our controlling class named Event01 to extend Frame, which extends Window, which extends Container, which extends Component.

Then, when we instantiate an object of our Event01 class, we have an object that can respond to all the events supported by Component.

The following main() method

I'm confident that by now you understand the statement that instantiates the object. We will discuss these GUI-related methods in more depth in a subsequent lesson.


  //Create and size the window
  public static void main(String[] args){
    Event01 displayWindow = new Event01(); //instantiate obj of this type
    displayWindow.resize(300,200);//set window size
    displayWindow.setTitle("Copyright 1997, R.G.Baldwin");
    displayWindow.show();//display the window
  }//end main

Overriding the handleEvent() Method

The next method that we will discuss is the overridden version of handleEvent(). When you override this method, your code will receive an object of type Event as a parameter when the method is called.

In this overridden version, we constructed a switch statement which tests the id field of the incoming object against the symbolic constants MOUSE_DOWN and WINDOW_DESTROY.

This version of the method doesn't attempt to handle any other events. This is a typical control structure for an overridden version of handleEvent(). The task at hand is to determine if the Event object passed to the handleEvent() method describes an event that is of any interest to the program.

For example, a click event on a text area which has been installed in a read-only mode might not be of any interest to the program, and might simply be an accidentally click on the part of the user.

Before returning to the runtime system, this method calls handleEvent() in the superclass using the super keyword and passing the Event object in as a parameter. This is done so that any events not handled in the overridden version of the method will be handled (in the default manner) by the handleEvent() code at a higher level in the inheritance hierarchy.

For the case where the id of the event matches WINDOW_DESTROY, our program simply terminates the program by calling System.exit(0). In this case, there is no need to call the handleEvent() method in the superclass. This happens when the user closes the event by clicking the X-button in the upper right-hand corner of the window.

For the case where the id of the event matches MOUSE_DOWN, we actually process the event by making a call to an event-handling method of our own design.

Note that the custom event handler is so small that we could reasonably have coded it into the switch statement. However, to keep things clean, we broke it out as a separate method named myMousDwnEvntHandler(int x, int y). When we called the method, we extracted the x and y values from the Event object and passed them in as parameters.


  public boolean handleEvent(Event evntObj){     switch(evntObj.id){//determine the type of event       case Event.MOUSE_DOWN : myMousDwnEvntHandler(evntObj.x, evntObj.y);                               break;       case Event.WINDOW_DESTROY : System.exit(0);     }//end switch     return super.handleEvent(evntObj);                         }//end handleEvent()

Our Custom Event-Handler Method

Now we are going to discuss the custom event handler named myMousDwnEvntHandler().

To this point, we have managed to avoid much in the way of GUI code. However, we are about to see some and will need to explain it briefly.

When you program in a GUI mode in Java, all output to the screen is in the form of bitmaps. Placing these bitmaps on the screen is often referred to as painting the screen. In fact, there is a method named paint() which is a member of the Component class that we can use to control how our material is placed on the screen

We never actually call the method named paint(). Rather, we call a method named repaint() instead. When we override paint() and call repaint(), this causes our overridden version of paint() to be invoked. When it is invoked, an object of type Graphics is passed in as a parameter. This object is actually the graphical representation of the screen inside our window.

This gives us access to the screen in a graphics mode and we can place whatever we want to see on the screen at that point. As you might suspect, the Graphics class provides a number of useful methods that we can call to place our material on the screen.

So, our custom event handler


  public void myMousDwnEvntHandler(int x, int y){
    clickX = x; //save mouse coordinates
    clickY = y;
    msg = "" + x + ", " + y; //construct message for display
    repaint(); //force a repaint of the window
  }//end myMousDwnEvntHandler()

Overriding the paint() Method

That brings us down to the paint() method proper. There are several overloaded versions of repaint() which control the portion of the screen that will be repainted. Painting the screen is a fairly expensive process. Therefore, in some cases where we know that only a small portion of the screen has changed, we can avoid having to repaint the entire screen.

In our case, we didn't make any attempt to optimize. We simply called that version of repaint() that would invoke the paint() method on the full screen area inside our frame.

As you can see in the code below, our overridden paint() method is pretty simple. We simply invoke one of the methods of the Graphics class named drawString() to to cause our coordinate information to be "drawn" on the screen at the location specified by the x and y values of the mouse pointer.


  public void paint(Graphics g){
    g.drawString(msg, clickX, clickY);
  }//end paint()

Closing Remarks

If you compile and execute this program, you should notice a few interesting things. One thing to notice is that a Java frame produces a window that can be resized (by dragging its corners), moved (by dragging its title bar), minimized (by clicking the minimize icon), and maximized (by clicking the maximize button).

You might also notice, and this is a GUI preview issue, that when you minimize and then recover the window, any text which appears on the window is restored when the window size is restored. This is not a natural occurrence. I programmed it that way.

By explanation, although the runtime system automatically restores certain components (such as buttons) when a window is restored, graphic material of the type that we are using is not automatically restored.

The reason that it appears to be automatically restored is because the system automatically invokes the paint() method when the size of the window is restored.

Since we have overridden the paint() method and have added code to display our text on the screen. Our overridden version of paint() is automatically invoked, and it re-executes the code which displays the text on the screen.

If for some reason the instance variables used by paint() were to be modified while the window is minimized, it would display different results when the window is recovered.

-end-