| Component method | When it's called |
| action (Event evt, Object what) | When the "typical" event occurs for this component (for
example, when a button is pushed or a drop-down list item is selected) |
| keyDown (Event evt, int key) | A key is pressed when this component has the focus. The second argument is the key that was pressed and is redundantly copied from evt.key. |
| keyUp(Event evt, int key) | A key is released when this component has the focus. |
| lostFocus(Event evt, Object what) | The focus has moved away from the target. Normally, what is redundantly copied from evt.arg. |
| gotFocus(Event evt, Object what) | The focus has moved into the target. |
| mouseDown(Event evt, int x, int y) | A mouse down has occurred over the component, at the coordinates x, y. |
| mouseUp(Event evt, int x, int y) | A mouse up has occurred over the component. |
| mouseMove(Event evt, int x, int y) | The mouse has moved while it's over the component. |
| mouseDrag(Event evt, int x, int y) | The mouse is being dragged after a mouseDown occurred over the component. All drag events are reported to the component in which the mouseDown occurred until there is a mouseUp. |
| mouseEnter(Event evt, int x, int y) | The mouse wasn't over the component before, but now it
is. |
| mouseExit(Event evt, int x, int y) | The mouse used to be over the component, but now it isn't. |
You can see that each method receives an Event object along with some
information that you'll typically need when you're handling that particular
situation – with a mouse event, for example, it's likely that you'll want
to know the coordinates where the mouse event occurred. It's interesting
to note that when Component's handleEvent( ) calls any of these methods
(the typical case), the extra arguments are always redundant as they are
contained within the Event object. In fact, if you look at the source code
for Component.handleEvent( ) you can see that it explicitly plucks the
additional arguments
out of the Event object. (This might be considered inefficient coding
in some languages, but remember that Java's focus is on safety, not necessarily
speed.)
To prove to yourself that these events are in fact being called and as an interesting experiment, it's worth creating an applet that overrides each of the methods above (except for action( ), which is overridden in many other places in this chapter) and displays data about each of the events as they happen.
This example also shows you how to make your own button object because
that's what is used as the target of all the events of interest. You might
first (naturally) assume that to make a new button, you'd inherit from
Button. But this doesn't work. instead, you inherit from Canvas (a much
more generic component) and paint your button on that canvas by
overriding the paint( ) method. As you'll see, it's really too bad
that overriding Button doesn't work, since there's a bit of code involved
to paint the button. (If you don't believe me, try exchanging Button for
Canvas in this example, and remember to call the base-class constructor
super(label). You'll see that the button doesn't get painted and the events
don't get handled.)
The myButton class is specific: it works only with an AutoEvent "parent window" (not a base class, but the window in which this button is created and lives). With this knowledge, myButton can reach into the parent window and manipulate its text fields, which is what's necessary to be able to write the status information into the fields of the parent. Of course this is a much more limited solution, since myButton can be used only in conjunction with AutoEvent. This kind of code is sometimes called "highly coupled". However, to make myButton more generic requires a lot more effort that isn't warranted for this example (and possibly for many of the applets that you will write). Again, keep in mind that the following code uses APIs that are deprecated in Java 1.1.
Case Study: AutoEvent.java
You can see the constructor uses the technique of using the same name for the argument as what it's assigned to, and differentiating between the two using this:
this.label = label;The paint( ) method starts out simple: it fills a "round rectangle" with the button's color, and then draws a black line around it. Notice the use of size( ) to determine the width and height of the component (in pixels, of course). After this, paint( ) seems quite complicated because there's a lot of calculation going on to figure out how to center the button's label inside the button using the "font metrics". You can get a pretty good idea of what's going on by looking at the method call, and it turns out that this is pretty stock code, so you can just cut and paste it when you want to center a label inside any component.
You can't understand exactly how the keyDown( ), keyUp( ), etc. methods
work until you look down at the AutoEvent class. This contains a Hashtable
to hold the strings representing the type of event and the TextField where
information about that event is held. Of course, these could have been
created statically rather than putting them in a Hashtable,
but I think you'll agree that it's a lot easier to use and change.
In particular, if you need to add or remove a new type of event in AutoEvent,
you simply add or remove a string in the event array – everything else
happens automatically.
The place where you look up the strings is in the keyDown( ), keyUp(
), etc. methods back in MyButton. Each of these methods uses the parent
handle to reach back to the parent window. Since that parent is an AutoEvent
it contains the Hashtable h, and the get( ) method, when provided with
the appropriate String, will produce a handle to an Object that
we happen to know is a TextField – so it is cast to that. Then
the Event object is converted to its String representation, which is displayed
in the TextField.
It turns out this example is rather fun to play with since you can really
see what's going on with the events in your program.