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.
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
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.
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.
The default behavior of handleEvent() (as indicated by the following code) is to
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; }
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.
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
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
//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
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()
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()
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()
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-