Events are now handled in a more efficient way in Java version 1.6 or later. This essay describes the old technique. See my essay on the Java version 1.1 or later event model. I suggest you read some other essays on events such as Richard Baldwin’s instructional essays
The java.awt class lets you write in a platform-independent way to hook into the native GUI API. The native GUI informs your application of various things the user has done by very indirectly generating event objects and passing them as parameters to the postEvent of the affected component which in turn hands it to the handleEvent method. Nothing is more confusing to the new Java programmer than events. They are doubly confusing because they work quite differently than in other windowing systems and because there is almost no documentation on how they work.
An AWT event has a life cycle something like the Pacific salmon. The salmon is born in a stream, migrates to the sea, then, if it isn’t killed in the ocean, returns to the stream where it was born and dies.
The AWT event starts in the native GUI, percolates up through the peer, button, panel, window in the Java application, and returns to the peer and back to the native GUI.
The best way to describe this is to hitch a ride on an event and watch how it percolates from birth to death on the event processing assembly line.
The loop that processes events does not even start until your main program has returned!! This event loop code is not visible to the application programmer.
The native GUI looks in the peers and/or its private tables to narrow down which app, and within that which panel, and within that which button was pressed and generates a native GUI event which is handed over to the corresponding ButtonPeer object in the AWT (Advanced Windowing Toolkit). Alternatively it may just create a native GUI event message.
The narrowing logic all happens totally behind the AWT’s back. It is the native GUI’s problem to figure out which component in a container was clicked by analysing x-y coordinates and comparing them with bounding rectangles.
The native GUI may change the look of the button at this point, e.g. to make it look pressed. The peer object and native GUI will get a second crack at processing the event later, but it most likely will do all of its processing now.
Sometimes the native GUI handles dispatching — finding the corresponding peer object to give the event to. Sometimes the AWT peer logic has to do it. Application programmers need not concern themselves with either narrowing or dispatching.
From the Java programmer’s point of view an event magically appears at the bottom of the hierarchy directly at the corresponding ButtonPeer object.
The AWT then constructs a Java-style corresponding event object to announce that a button has been clicked.
handleEvent then classifies the event and hands it off to more specific event handlers like mouseDown, and action.
If the button’s handleEvent returns true it means kill the event. Returning true means the event is totally and completely handled and nothing further should be done with it anywhere. If the event handler returns false it means there is still more to be done with this event. The event handler may or may not have modified the event object or done some work behalf of the button-pressing quite independently of whether it returns true or false.
Normally it will return false. If it returns true, the event will never return to the native GUI, which may result in its effect being totally suppressed.
postEvent then looks at the return code from the button’s handleEvent. If it is true, it just returns, effectively killing the event. If the button’s handleEvent returns false, postEvent finds the button’s parent (not its superclass!) i.e. its containing panel. It transforms the x,y in the event object into the coordinate system that the parent panel uses — i.e. where in the entire panel the mouse was clicked. handleEvent then calls postEvent of the button’s parent — i.e. the panel containing the button — handing it the same event object.
The event percolates up the tree, until either somebody handles it and kills it or it bubbles off the top and is handled back to the ButtonPeer object i.e. back to the native GUI. Java In A Nutshell shows code modeled on the old model of event handlers, where typically the default handleEvent for the generic button would do nothing, just return false. The button’s postEvent would then pass the event onto the enclosing panel. The panel’s handleEvent would classify the event, and pass it on to the panel’s action. action would typically be an overridden application method that figures out which of the panel’s buttons had been pressed by examining the Event.Target, and Event.arg fields (happily examining x,y is usually NOT necessary). action would then finally do something useful — like display a graph — i.e. whatever the user wanted to happen when she clicked the button.
The panel’s handleEvent then would return true to indicate everything that needs to happen as a result of the button being pressed is now complete. This kills the event and stops further percolation.
In the new model, all works the same, except that every event handler returns false so that the event continues to percolate all the way back to the native GUI again.
Some programmers might prefer to write an overriding handleEvent for the individual button that directly called the relevant application code, to create a classes of smart components that could accept callback delegate objects.
A parent cannot censor what keystrokes its children see. Event percolation works the other way around. The kids alone decide what they want their parents to know.
Let us say that the user hit the Z key while the focus was on a listbox (java.awt.Listawt.List) component. Her intent is to select Zebra from a list of animals presented.
The KEY_PRESS event starts at the bottom at the peer listbox component’s postEvent. The peer hands the event off to the AWT listbox component by calling its postEvent. The event would normally percolate all the way to the top without modification or any other action. The handleEvent for each level would just return false. Event handlers may optionally modify the event.key or the event.modifiers on the way through. If any event handler returns true, that stops dead any further processing of the keystroke. It will be as if the Z key had never been pressed.
If the KEY_PRESS event successfully percolates all the way to the top with no event handler killing it, it eventually reaches the list box peer component again. The peer then hands the (possibly-modified) keystroke back to the native GUI for further processing. Now, when it sees the event for the secord time, the native GUI does the bulk of the keystroke processing work. This contrasts with button processing where the bulk of the native GUI work happens before the event percolates.
How the work is split between the peer and the GUI and the awt component is still in flux.
Unfortunately the answers to these questions are not yet documented. Your best bet is to just see what sorts of events arrive and code to that, then test your code on other platforms and adjust until it finally works everywhere. Ouch!
The lack of documentation on event processing may be deliberate. I think the idea is your program should not depend on how the AWT works inside. This has deliberately been left undefined. Your code should fly even if there is only a single thread processing all paint requests and events. Some may claim it should also fly even if there are 10,000 threads attempting to process every event fully simultaneously even for the same component. If you need serialization, you should be using synchronised methods.
Instead, spin off time-consuming work to be done on a new thread, or enqueue it to be done later by a fixed set of worker threads that process work request packets in the background. Be wary of thread fission.
In some systems, your repaint logic can’t even start until the current event has been completely handled. Doing a Thread.sleep just stalls event processing, making matters even worse. Don’t go to sleep in the middle of processing an event!
You might think the best way to a handle a time-consuming event handling task is to do some of the work then post an event to yourself to tell you where to carry on later, as you might under Windows 3.1. This won’t work. postEvent does not enqueue events. It does not return until the posted event has been totally handled. You could of course invent your own queuing mechanism.
The native GUI enqueues this request. As windows occlude each other and reveal each other, the native GUI itself decides that certain components, or parts of components also need to be repainted. The native GUI merges all these requests and removes the duplicates. It may reorder them so that background panels are repainted before the overlaying components.
Eventually the GUI will call the update method for a component to be painted, passing it a graphics object describing the region on the screen to be updated complete with clipping region, since quite likely only part of the component needs to be repainted.
The update and paint routines just paint the entire component. They don’t need to be aware of the clipping.
update then typically erases the region using a fillRect and calls paint. A side effect of this painting will be that some of the subcomponents will be overlaid and will need to be repainted. It is not the concern of update nor paint to arrange for this. The native GUI handles that logic all by itself. No application code need concern itself with the problem.
Don’t dawdle in a paint routine. In pracitice, no other painting can be done until your routine completes. In theory, painting is handled by a separate thread from the event handling and can run in parallel, but it seems in practice any stalling in either paint or event processing sometimes holds everything up.
This page is posted
Optional Replicator mirror
|no blog for this page||Canadian
Your face IP:[188.8.131.52]
You are visitor number|