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, Program-Generated Events

Java Programming, Lecture Notes # 68, 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.

Previous lessons have taught you how to override the handleEvent() method of the Component class and also how to override convenience methods of the Component class in order to respond to events.

In this lesson, we take the subject of event handling one step further by teaching you how to create and distribute Event objects under program control which produce the same response as if the event were caused by an action of the user.

In other words, you can create and distribute Event objects which simulate the behavior of a user.

Recall that you can handle any event by overriding the handleEvent() method.

The handleEvent() method is invoked by the runtime system whenever any event occurs.

(As mentioned in an earlier lesson, the statement above is an oversimplification because there is another method named postEvent() which is also involved in an important way. However, for the purposes of this discussion, we can think in terms of the runtime system communicating directly with the handleEvent() method.)

The fact that you can handle any event by overriding the handleEvent() method continues to be true even if the event is generated by the program as opposed to being generated by a user.

In this lesson, we will not use the convenience methods for handling events. Rather, we will handle all events by overriding the handleEvent() method. I believe that this will provide for consistency and make the material easier to understand.

How to Create and Distribute an Event

The process for creating and distributing an event is amazingly simple. You simply The only part that requires much though is determining what to put into each of the fields of the object.

The constructors for the Event class are shown below (per API Documentation 1.0.2).

    public Event(Object  target, int  id, Object  arg);
    public Event(Object  target, long  when, int id,
              int  x, int  y, int  key, int  modifiers);
    public Event(Object  target, long  when, int id,
                   int  x, int  y, int  key,
                   int  modifiers, Object  arg);
It is not necessary to put valid information in every field in the object. You only need to put information in those fields that will be used by the event handler for the event.

These three overloaded versions of the constructor allow you to put information in selected subsets of fields to support the event handler that will be invoked when the Event object is distributed.

In some cases, you may put "dummy" information in a field if you know that the event handler won't be using information from that field. For example in the sample program later in this lesson, we put a dummy string in the arg field because we know that the event handler won't be using information from that field.

To review the material from an earlier lesson, according to API Documentation 1.0.2, the fields of the object and their purposes are listed below.

Therefore, to create and distribute an event Note that the postEvent() method can also be used for this purpose, and I will leave it as an exercise for the student to ferret out the similarities, differences and relationship between these two methods. Hint: See the API Documentation from JavaSoft.

Critical Fields

Two of the fields in the Event object are critical and should be correctly specified in all cases, otherwise the event may not land anywhere or do anything worthwhile (it would be like an event of no particular type with no particular place to go): The id field is used to specify the type of event using the symbolic constants defined in the Event class and presented in an earlier lesson. (Although not recommended, you can use integer values to specify the type of event if you know the correct value for the integer.)

The target field is used by the system to determine which component to deliver the Event object to. For example, to simulate a click on a specific Button component, you should create an Event object of the ACTION_EVENT type with the specific Button object specified as the target.

Sample Program

The sample program for this lesson is shown below. A great deal of information about this program is provided in the comments at the beginning. Each of the sections of the handleEvent() method is discussed in detail following the listing of the program.


/*File Event03.java Copyright 1997, R.G.Baldwin
Primarily designed to illustrates program-generated events.

A frame contains a Button and a TextField.  When the user
clicks the Button, a counter is incremented and displayed
in the TextField.

If the user clicks in the blank area of the frame, the counter
is reset and the coordinates of the mouse pointer are displayed.

If the user presses the b or B keys, a KEY_PRESS event is detected,
which causes an ACTION_EVENT object to be created and delivered to 
the Button by using the deliverEvent() method.  The result is the 
same as if the Button had been clicked.  This is a program-generated 
event.

Closing the frame terminates the program.

Note that there are some focus issues that are not handled in an
ideal manner in order to preserve simplicity.  In particular, if
the first thing that you do is to press the b or B key, nothing
happens.

*/

import java.awt.*;

//Make the controlling class extend the Frame class
// to produce a graphic window that can accept events.
public class Event03 extends Frame{
  String msg = ""; //save message for display here
  int clickX = 0, clickY = 0;//save coordinates for display here
  Button myButton; //used to instantiate a button object
  TextField myTextField; //used to instantiate a TextField object
  int counter = 0;

  //Because this display is a little more complicated than before
  // we will to use a constructor to build it.  
  public Event03(){//constructor
    //put a button at the top of the frame
    myButton = new Button("Click Here to Increment Counter");
    add("North", myButton);//add it to the top of the frame  
    
    //put a non-editable TextField at the bottom of the frame
    myTextField = new TextField(
      "counter = " + counter + "     This textField is not editable.");
    add ("South",myTextField);//add it to the bottom of the frame
    myTextField.setEditable(false);//make it non-editable

    //Dress the frame up a little    
    setTitle("Copyright 1997, R.G.Baldwin");
    resize(300,200);//set frame size    
   }//end constructor

  //Create and display the frame
  public static void main(String[] args){
    Event03 displayWindow = new Event03(); //instantiate obj of this type
    displayWindow.show();//display the frame
  }//end main
  
  //Override  handleEvent() method in Component class
  // to process all events.
  public boolean handleEvent(Event evObj){
    //Terminate program if user closes the window
    if(evObj.id == Event.WINDOW_DESTROY) System.exit(0);
    
    //Display the coordinates and clear the counter when user clicks 
    // in blank portion of the frame.
    if( (evObj.id == Event.MOUSE_DOWN) && (evObj.target == this)){
      clickX = evObj.x; //save mouse coordinates
      clickY = evObj.y;
      //construct message for display
      msg = "" + clickX + ", " + clickY + ", Clear counter";
      counter = -1;//clear the counter and modify text in the TextField
      myTextField.setText(
        "counter = " + ++counter  + "     This textField is not editable.");
      repaint(); //force a repaint of the window
    }//end if on MOUSE_DOWN in blank portion of frame
    
    //Create an action event object and deliver it to the button if the
    // user presses b or B.
    if( (evObj.id == Event.KEY_PRESS) 
      && ((evObj.key == 'b') || (evObj.key == 'B')) ){
      Event event = new Event(myButton,Event.ACTION_EVENT,"Dummy string");
      deliverEvent(event);
      //postEvent(event); could use postEvent() instead of deliverEvent()
    }//end if on KEY_PRESS

    //When the user clicks the button, (or a program-generated action event
    // is delivered to the button) increment the counter which
    // uses the textField as a display device.    
    if( (evObj.id == Event.ACTION_EVENT) && (evObj.target == myButton)){
      myTextField.setText(
        "counter = " + ++counter + "     This textField is not editable.");    
    }//end if on ACTION_EVENT
    
    //Always finish by invoking the handleEvent method in the superclass
    // to handle any events not handled above.
    return super.handleEvent(evObj);                      
  }//end handleEvent()

  //Override paint method to repaint the window.  This displays 
  // graphic coordinate information in the blank area of the frame.
  public void paint(Graphics g){
    g.drawString(msg, clickX, clickY);
  }//end paint()
  
}//end class Event03
To begin with, we needed a little more GUI in this program than in previous programs in order to have enough tools available to illustrate the concept of program-generated events.

In addition to the Frame object that we have been using in previous programs, we also needed a Button component and a TextField component.

The Button is used to increment a counter whenever it is clicked.

The TextField is used to display the value of the counter.

For the time being, please just accept the fact that the code in the constructor will produce the desired user interface.

We will discuss the issues surrounding the creation of user interfaces using components in detail in several subsequent lessons.

The code that is really of interest here is

Let's examine the overridden handleEvent() method on a section-by-section basis.

We will skip over the section that responds to the WINDOW_DESTROY event to terminate the program. You have seen that before and we didn't make any significant changes in that area.

Display Mouse Coordinates and Reset the Counter

First consider that portion of the method that displays the coordinates of the mouse and resets the counter when the user clicks in the blank portion of the Frame.

    if( (evObj.id == Event.MOUSE_DOWN) && (evObj.target == this)){       clickX = evObj.x; //save mouse coordinates       clickY = evObj.y;       //construct message for display       msg = "" + clickX + ", " + clickY + ", Clear counter";       counter = -1;//clear the counter and modify text in the TextField       myTextField.setText(         "counter = " + ++counter  + "     This textField is not editable.");       repaint(); //force a repaint of the window     }//end if on MOUSE_DOWN in blank portion of frame
This code starts out by cracking open the Event object and confirming the occurrence of a MOUSE_DOWN event on the Frame object (represented by this).

Then, as in earlier sample programs, the code sets up some information to be displayed by the paint() method when it is invoked, either by calling repaint() or because of some system activity such as restoring the display when things are moved about by the user. You have seen this before.

After that, the code executes some fairly straightforward statements to reset the counter variable to zero and display its value. Then it calls repaint() to force the graphics portion of the display to be repainted.

Except for the fact that this was all included inside the overridden handleEvent() method instead of using a convenience method, there's not much that is too difficult here.

Create an Action Event and Deliver it to the Button

This is the most important part of this entire lesson (and it all happens in three lines of code).

The following code will create an Event object of type ACTION_EVENT and deliver it to the Button object for processing.

The event is created and delivered whenever the user presses the "b" key or the "B" key on the keyboard. The end result of pressing either of these keys is the same as clicking the button with the mouse.


    if( (evObj.id == Event.KEY_PRESS)        && ((evObj.key == 'b') || (evObj.key == 'B')) ){       Event event = new Event(myButton,Event.ACTION_EVENT,"Dummy string");       deliverEvent(event);       //postEvent(event); could use postEvent() instead of deliverEvent()     }//end if on KEY_PRESS
As you can see, the code required to create and distribute a program-generated event is amazingly simple.

This code fragment starts out by responding to an event of type KEY_PRESS and confirming that it was the result of pressing either the lower-case or upper-case "B" key. Unless both conditions are satisfied, the code fragment ignores the event leaving it up to handleEvent() to deal with later.

If both conditions are satisfied, the code fragment instantiates a new object of type Event with

It was known in advance by the author of the program (yours truly) that the event handler for the action event on the button would ignore the third parameter, so it was simply passed in as a dummy string.

The the code fragment invokes the deliverEvent() method to cause the the system to deliver the new Event object to the Button object. This causes the program to behave as though the Button object had received an ACTION_EVENT directly (such as being clicked by the user).

As mentioned earlier, the postEvent() method could also have been used for this purpose, but I am leaving it as an exercise for the student to ferret out the differences, similarities, and relationship between these two methods.

Processing an Action Event on the Button

When the user clicks the button, (or a program-generated action event is delivered to the button) the following code fragment will increment the counter variable and display the value of the counter in the textField.


    if( (evObj.id == Event.ACTION_EVENT) && (evObj.target == myButton)){
      myTextField.setText(
        "counter = " + ++counter + "     This textField is not editable.");    
    }//end if on ACTION_EVENT
There isn't a lot to be said about this code. It simply verifies that the event is an ACTION_EVENT and that the specific Button object is the target, and then increments and displays the counter variable.

Wrapup, Handling Unhandled Events

Whenever you override the handleEvent() method, you should either specifically handle all possible events (which is probably impractical) or invoke the handleEvent() method one level up so that it can deal with any events that you did not deal with specifically. That can be accomplished as follows:
   
    //Always finish by invoking the handleEvent method in the superclass
    // to handle any events not handled above.
    return super.handleEvent(evObj);                      
  }//end handleEvent()
-end-