A Peak In the Abstract Window Toolkit
This week we're going further into the new Abstract Window Toolkit (AWT) in the recent upgrade of the JDK.Of the existing Java features, this one is not only the most integral to writing Java applets, but the most changed in this upgrade; we've certainly written our share about it. Our reaction to the old AWT version has been, on the whole, satisfactory, although there are some sore points, and (we're told) feelings are generally mixed. Apparently JavaSoft has heard that as well.
What's really different? Some names have changed. The model for handling events has been redone. Most importantly, there are some new features that obviate some old techniques a bunch of you may have been using. We're going to talk about the technical underpinnings of some of these changes. Yet herein lies a problem: as of right now, the only two "easy" ways for you, the reader, to examine an applet written with the new API are:
- The appletviewer included in the new JDK release
- The beta version of HotJava 1.0 now available from Sun.
The former is cumbersome. The latter, let's put it this way, on our Pentium 100 test machine, it was slow enough to make us very drowsy. Instead, we're going to restrict ourselves to theory and wait for Netscape to catch up with us.
In fact, we can't really hope to tackle all the important new parts of the upgrade in one week. There are a lot of little changes, all of which qualify, in our opinion, as deserving of our attention. This time around, we'll start with what we considered to be the most important change: the Delegation Event Model.
This is just more jargon, of course. To translate: Events are no longer dropped in your lap, so to speak. You must now delegate the responsibility of handling your events as an object (or objects).
To recap: In the 1.0 event handling model, your program became aware of activities regarding the GUI because any activity would call a handleEvent method, first in the component it originated in, and then in its container, and then in its container's container, and so on, until it reached the root, or some handleEvent method along the way elected to stop it.
If you wanted some activity in the GUI to start a piece of code, you would subclass a relevant AWT component and supply your own version of handleEvent. The built-in handleEvent in most every AWT component would, additionally, call "shortcut methods" that would make handling events even easier. If you wanted to do something when the mouse pressed down over your component, you could just make your own mouseDown shortcut method. We wrote about this extensively in previous issues and for several issues following.
We thought this was sufficient enough as it was. Sun, however, properly recognized that this could become cumbersome in big Java applications, since the two ways of handling events were:
- Subclass the interface objects (components)Ęthat needed to perform actions, or
- Subclass the component(s) that contain all the interface objects (by this we mean the buttons, lists, etc.) and make one big event handling method that checks for every event of interest.
Java code could become overburdened with lots of new versions of AWT objects that were necessary only to handle events they generated, and/or very large and ugly sets of if statements for handling all the events in a given program. Not to mention that events that occurred often, such as those describing movement of the mouse, would have to waste actual CPU time propagating through all the interface components that they occurred in.
Their solution was interesting. In the new Java, events are handled by listeners. Every AWT component now quietly sits on the events that occur within it unless it's been explicitly told (by the programmer) to delegate those events to a listener object.
Listeners can be any class you desire, including the AWT objects themselves; they only need to implement a listener interface. Once an object is listening for events, the event-triggered methods (which are specified by the interface) that you've written into it will be called if the event actually occurs.
In other words:
- Make a button
- Make a class that acts as a listener
- "Add" the listener to the button.
You add a listener to an interface object like so:
Button myButton; myButton = new Button("Button's Label"); add(myButton); // Adds the button to an Applet's display myButton.addActionListener(ourListener);In this example, ourListener is a listener class that we've created that implements a specific kind of listener interface called an actionListener. ActionListeners are a type of listener designed to handle generic "actions" on AWT objects. Buttons, for instance, are acted on when pressed.
This is the heart of what Sun calls "event filtering": The listener will only receive events of the kind it's been added (or, in other parlance, registered) for. Somewhere in the listener class is a method called actionPerformed; this method will be set off and passed an actionEvent whenever an action on any one of the AWT components it's registered to listen to occurs. You can write the method to do whatever you want in response.
As you can see, there's now a hierarchy of different types of Events, and a corresponding hierarchy of different types of Listeners. This actually does a fairly good job of organizing what would otherwise be a morass of different kinds of events and the routines that would handle them.
Still confused? We'll have some more examples coming soon. In the meantime, don't wait for us: Check out the AWT homepage; there's some good documentation there.
Join us again next week, when we'll pause again to look further at the new HotJava. In issues following we'll immediately return to this discussion.