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 Event-Handling Hierarchy and the postEvent() Method

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

The beta version of JDK 1.1 is available for testing at this time, and 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.

There may be some confusion in your mind about the earlier discussions of passing events up the container hierarchy. If so, we will try to clear up that confusion in this lesson.

In a previous lesson, we described how user actions involving GUI components get converted into messages by the operating system, and how those messages are sent to the Java runtime system.

We said that when this happens, the Java runtime system

We pointed out along the way that this is an oversimplification which ignores the involvement of another method named postEvent().

In this lesson, we will describe how the postEvent() method comes into play and how it relates to handleEvent(). As an aside, we will also describe how it relates to the deliverEvent() method.

We explained that if handleEvent() returns false, the event is passed up to the next container in the container hierarchy.

In this lesson, we will write a program which constructs just such a container hierarchy and will be able to watch an event being passed up the line as the program executes.

We also explained that if handleEvent() returns true, the event will be stopped at that level and will not be passed up to the next container in the hierarchy.

The process of passing the event up the line continues until the handleEvent() method at some level returns true, or there are no more containers to pass it up to.

A More Accurate Description of the Process

According to Exploring Java by Patrick Niemeyer and Joshua Peck, The following is a description of postEvent() as extracted from JavaSoft's API Documentation:


public boolean postEvent(Event evt) 

     Posts an event to this component by calling its handleEvent method. 
     If handleEvent returns false, the event is posted to this 
     component's parent. 

     If this component and all of its parents return false, the event 
     is passed to this component's peer object's handleEvent method. 

     Parameters: 
          evt - the event 
     Returns: 
          true if this component, one of its parents, or this 
            component's peer handled the event;
          false otherwise. 
     See Also: 
          deliverEvent.
The above information introduced another new term: peer.

According to the Glossary in Exploring Java,

What this all says is that the runtime system actually calls postEvent() rather than calling handleEvent() directly and the runtime system passes the Event object as a parameter to the postEvent() method.

It is the postEvent() method that actually implements the processing of passing events up the hierarchy from one container to the next.

At each point along the way, postEvent() invokes handleEvent() which may return either true or false.

If true is returned at any level, the postEvent() method terminates the process. Otherwise, it passes the event up to the next postEvent() method in the container hierarchy which repeats the action.

Eventually, when postEvent() runs out of containers, the event is passed to another part of the system for default handling, if any.

The postEvent() and deliverEvent() Methods

We're going to take a short side trip which also involves the postEvent() method.

In an earlier lesson when we were creating program-generated events, we said that we could deliver the program-generated event to the recipient using either deliverEvent() or postEvent(). Let's look at the reason that either method could be used.

The following description of deliverEvent() was extracted from the API Documentation.


public void deliverEvent(Event evt) 

     Delivers an event to this component or one of its subcomponents. 

     The deliverEvent method of Component calls the component's 
     postEvent method on the event. 

     Parameters: 
          evt - the event
Apparently based on the above, deliverEvent() simply calls postEvent() and passes the event along as a parameter. That is why you can use either. I haven't found anything indicating a downside to calling postEvent() directly from your program, but as usual there may be one lurking somewhere. Otherwise, there would be no need for the existence of deliverEvent() in the first place.

A Sample Hierarchy Program

Later when we study the creation of Graphical User Interfaces, we will learn that in order to achieve the desired layout, appearance, and behavior, it is often necessary to subdivide an overall interface into separate containers, each of which can contain components or other containers.

The following program is not intended to demonstrate effective interface design. However, it is intended to illustrate the process by container hierarchies can be established. This leads naturally to the study of events propagating up the container hierarchy.

I will not provide much in the way of a written discussion of this program other than the discussion in the comments at the beginning of the program, because there isn't much here that is new.

We will be using a new term: Panel. In Java, a Panel is a class in the java.awt package which can be used to instantiate container objects.

A Panel can't be seen. It is simply a place to put other components in some desired arrangement.

The Panel and its components, with their specific arrangement, can then be treated as a single object which can be placed along with other such objects into another container.

That is how the container hierarchy is built up.

Take a look at the following program. Although the program is fairly long, it is repetitious.

A description of the program is given in the comments at the beginning.

If you compile and run this program, you should see a column of objects containing three TextField objects and one Button object. The button is at the bottom, and the top-level TextField object is at the top.

If you click the Button object, you should see the text in each of the TextField objects change, with a one-second delay between the changes in the TextField objects, going from bottom to top. This simulates the Event object being propagated up the container hierarchy.

At this point, you shouldn't worry about the layout manager code which I needed to use. Suffice it to say that a layout manager is there to help you arrange components in a container.

There are several different styles of layout manager available. The one being used here is a border layout manager. This layout manager can be used to place up to five objects in a container: one in the center, and the other four in the North, South, East, and West positions.

What you do need to pay particular attention to is how the container and its components is instantiated into an object which simply becomes one of the components in the next higher-lever container.

This is the key to the GUI container hierarchy which we have been discussing for several lessons.


/*File Event04.java Copyright 1997, R.G.Baldwin
Illustrates the propagation of an event up through the
GUI object hierarchy, from container to container, to 
container, etc.

A Frame is created at the top level which contains a TextField 
and a Panel.

The Panel in the frame contains a TextField and another Panel.

That Panel contains a TextField and a Button. Thus, the Panel
containing the TextField and the Button are at the innermost
level of the hierarchy.

When the button is clicked, an ACTION_EVENT is generated on the
Button.  The handleEvent() method of the innermost container is 
used to put a message in the TextField.  The handleEvent() method 
returns false to cause the event to propagate up to the next
container in the hierarchy.

Because the method returns false, the system passes the event to
the handleEvent() method in the next container up the line.  That 
method puts a message in its TextField and returns false as well.

Again, because the handleEvent() method returns false, the event 
is then passed up to the next level which is the top level container.
The handleEvent() method in the top-level container puts a message in 
its TextField, invokes super.handleEvent(), and exits.

In summary, as the event propagates up through the hierarchy, 
the handleEvent() method of the container at each level displays 
a message and passes the event along.  Thus, messages are generated 
at all three levels as the event is propagated upward.

To make it easier to see what is happening, a one-second delay is
implemented in each event handler before the new text is actually
displayed.

Depending on the resolution of your screen, you may need to change
the size of the frame to make all three TextFields visible.

The following code is presented in an innermost to outermost order.
*/

import java.awt.*;

class ThirdLevel extends Panel{ //define class for innermost container
  Button myButton;//reference variable for Button object
  TextField myTextField;//reference field for TextField object
  
  ThirdLevel(){//constructor
    setLayout(new BorderLayout());
    myButton = new Button("click here");//instantiate Button object
    add("South",myButton);
    myTextField = new TextField("TextField, Third Level");//TextField object
    add("North",myTextField);
    resize(preferredSize());
  }//end constructor for ThirdLevel class
  
  //Event handler for innermost container
  public boolean handleEvent(Event evObj){//confirm Button action event
    if( (evObj.id == Event.ACTION_EVENT) && 
        (evObj.target == myButton) ){
      try{Thread.currentThread().sleep(1000);
      }catch(InterruptedException e){}//do-nothing exception handler
      myTextField.setText("Third Level ACTION_EVENT");
    }//end if
    return false;//pass the event up to the next container
  }//end handleEvent()  
}//end class ThirdLevel

class SecondLevel extends Panel{//class for middle-level container, panel
  ThirdLevel myThird;
  TextField myTextField;
  
  SecondLevel(){//constructor
    setLayout(new BorderLayout() );
    myThird = new ThirdLevel();//instantiate innermost container as an object
    add("South",myThird);
    myTextField = new TextField("TextField, Second Level");
    add("North",myTextField);
    resize(preferredSize());
  }//end constructor for SecondLevel class
  
  public boolean handleEvent(Event evObj){
    //Confirm that the event is an action event that originated     
    //at the button in the innermost container.
    if( (evObj.id == Event.ACTION_EVENT) && 
        (evObj.target == myThird.myButton) ){
      try{Thread.currentThread().sleep(1000);
      }catch(InterruptedException e){}//do-nothing exception handler
      myTextField.setText("Second Level ACTION_EVENT");
      }//end if
    return false;//pass the event on up the line
  }//end handleEvent()  
}//end class SecondLevel

//This is the class for the outermost container which is the controlling
// class for the application.  Make it extend the Frame class to produce
// a window that can accept events.
public class Event04 extends Frame{
  SecondLevel mySecond;
  TextField myTextField;
  
  Event04(){//constructor
    setLayout(new BorderLayout(1,3));
    mySecond = new SecondLevel();//Instantiate middle container as object
    add("South",mySecond);
    myTextField = new TextField("TextField, Top Level");

    add("North",myTextField);
    setTitle("Copyright 1997, R. G. Baldwin");
    resize(300,110);
  }//end constructor for Event04 class
  
  public boolean handleEvent(Event evObj){
    if(evObj.id == Event.WINDOW_DESTROY) System.exit(0);  

    //Test to determine if the event is an action event generated by 
    // the button in the innermost container.  Note the use of two 
    // dot operators to reference that Button object.
    if( (evObj.id == Event.ACTION_EVENT)&& 
        (evObj.target == mySecond.myThird.myButton) ){
      try{Thread.currentThread().sleep(1000);
      }catch(InterruptedException e){}//do-nothing exception handler
      myTextField.setText("Top Level ACTION_EVENT");
    }//end if
    return super.handleEvent(evObj);        
  }//end handleEvent()

  public static void main(String[] args){
    Event04 obj = new Event04(); //instantiate an object
    obj.show(); //and display it
  }//end main
}//end class Event04
-end-