13.7 Inheriting a component



Another place where you'll often see variations on the old way of doing things is when creating a new type of component. Here's an example showing that here, too, the new way works:

Case Study: GoodTechnique.java

This example also demonstrates the various events that occur and displays the information about them. The class Display is a way to centralize that information display. There's an array of Strings to hold information about each type of event, and the method show( ) takes a handle to whatever Graphics object you have and writes directly on that surface. The scheme is intended to be somewhat reusable.

EnabledPanel represents the new type of component. It's a colored panel with a button at the bottom, and it captures all the events that happen over it by using inner listener classes for every single event except those in which EnabledPanel overrides processEvent( ) in the old style (notice it must also call super.processEvent( )). The only reason for using this method is that it captures every event that happens, so you can view everything that goes on. processEvent( ) does nothing more than show the string representation of each event, otherwise it would have to use a cascade of if statements to figure out what event it was. On the other hand, the inner listener classes already know precisely what event occurred. (Assuming you register them to components in which you don't need any control logic, which should be your goal.) Thus, they don't have to check anything out; they just do their stuff.

Each listener modifies the Display string associated with its particular event and calls repaint( ) so the strings get displayed. You can also see a trick that will usually eliminate flicker:

You don't always need to override update( ), but if you write something that flickers, try it. The default version of update clears the background and then calls paint( ) to redraw any graphics. This clearing is usually what causes flicker but is not necessary since paint( ) redraws the entire surface.

You can see that there are a lot of listeners -- however, type checking occurs for the listeners, and you can't listen for something that the component doesn't support (unlike BadTechnique.java, which you will see momentarily).

Experimenting with this program is quite educational since you learn a lot about the way that events occur in Java. For one thing, it shows a flaw in the design of most windowing systems: it's pretty hard to click and release the mouse without moving it, and the windowing system will often think you're dragging when you're actually just trying to click on something. A solution to this is to use mousePressed( ) and mouseReleased( ) instead of mouseClicked( ), and then determine whether to call your own "mouseReallyClicked( )"  method based on time and about 4 pixels of mouse hysteresis.
 

Ugly component inheritance

The alternative, which you will see put forward in many published works, is to call enableEvents( ) and pass it the masks corresponding to the events you want to handle. This causes those events to be sent to the old-style methods (although they're new to Java 1.1) with names like processFocusEvent( ). You must also remember to call the base-class version. Here's what it looks like:

Case Study: BadTechnique.java

Sure, it works. But it's ugly and hard to write, read, debug, maintain, and reuse. So why bother when you can use inner listener classes?


Next Page