Innovative ways to handle events in AWT and JFC
Learn six different ways to connect event sources with target objects
The Abstract Windowing Toolkit (AWT) and Java Foundation Classes (JFC) use predefined listener interfaces to add behavior
to all of their GUI and non-GUI controls. Since event-handling code needs direct access to UI controls that generate events,
developers use inner and anonymous classes to implement event-listener interfaces. The JDK 1.1 specification forces compiler
implementations to be compatible with the JDK 1.0 class format. For this reason, the compiled units (class files) for inner
and anonymous classes tend to consume more bytes than necessary.
This article throws light on the problems inherent in traditional event-handling implementations using AWT/JFC and demonstrates
six ways to get around them.
Note: This article assumes that the reader has a thorough understanding of the AWT event model. Experience with the Reflection
API is necessary to modify or extend the five utility classes provided in this article.
Event handling in the JDK
Before getting into the guts of the system, let's take a quick peek at the event model mechanism in AWT and JFC.
The event source (typically a UI component) emits events through a predefined listener interface. Any object interested in
those events will register an implementation of the listener with the event source through an
addXXXListener() method. Except for
DocumentEvent, the rest of the events derive from the
java.util.EventObject class. This is the essence of the event model; anything else is implementation detail. To get some background on the AWT/JFC
event model, see the Resources section at the end of the article.
There are some outstanding issues with current event-handling implementations:
- Large UI implementations generally result in many anonymous or inner classes.
- Adapter classes are not defined for many event listener interfaces in JFC. In JDK 1.2, there are 49 listeners and only 9 adapters.
- Adapters cannot be used if the implementing class has to derive from some other class.
- Many developers use object diagrams to understand the interconnections between different types of objects. Many IDEs automatically
generate object diagrams from the source code. These diagrams help developers understand applications quickly without getting
lost in implementation details. Some tools fail to digest inner classes; others generate too many crisscrossing lines due
to those same inner classes. Object diagrams for the UI code are difficult to comprehend due to the many connecting lines
between event generators (UI controls), event handlers (inner or anonymous classes), and listener interfaces. Most of the
time, after generating the object diagrams, developers go back to remove inner class objects from the diagram to improve clarity.
- Some IDEs generate too much boilerplate code to connect GUI components with event handler methods. Large amounts of glue code
results in code bloat and large class files, which is a definite concern for applets.
- Due to the backward compatibility requirements of compiler specifications, inner and anonymous classes result in a large applet
or application footprint.
- Inner classes cannot derive from adapters if they are already deriving from another base class.
Innovative ways to handle events
The new approach introduced in this article attempts to address the issues listed above by using a few magic classes. I will
demonstrate how you can connect event sources and event-handling code using any one of the following six methods:
- Standard mechanisms:
- Using anonymous classes
- Using inner classes
- Not using inner or anonymous classes
- New alternatives:
EventHandler connects the event source and target object at the object level
EventListener connects the event source and target objects at the method level using a predefined listener class
GenericListener connects the event source and target objects at the method level by dynamically creating a custom listener implementation
To improve readability of the article, I have chosen to present a very simple UI implementation. Let's walk through it using
a simple program that displays two toggling buttons in a
Frame. The program also handles the system-close event to dispose of the
Frame. The same example is presented for each of the utility classes listed above. The following three example programs use standard