| Home > Core Java FAQ
> Event Handling FAQ |
| Event
Handling |
| Events
in 1.0 (11) * Event Classes,
Listeners, and Methods (08) * Semantic
Events (04) * Low-Level Events (04) |
| |
|
Q . What information can be carried in the JDK 1.0.2 by an Event object?
|
Ans :
Event
objects in the JDK 1.0.2 can carry information about the event's
source, the event type, when and where the event occurred, the
state of the keyboard for the event, and the state of the
component affected by the event; this information is carried in a
set of public fields, as listed in Table 6.1.
Table
6.1: Public Fields in an Event object—JDK
1.0.2
target |
the
object targeted for the event, for example, a TextField
instance receiving a mouse click |
id |
an
integer indicating the type of event, for example, Event.ACTION_EVENT |
when |
the
time stamp for the event, in milliseconds |
x,
y |
the
location of the event, in the coordinates of the
component receiving the event |
key |
the
key that was pressed or released to generate the event |
vmodifiers |
the
state of the modifier keys, such as shift and control |
arg |
an
additional, general purpose Object
parameter |
|
|
Q . What information do specific event types in the JDK 1.0.2 carry?
|
Ans :
Too much to
answer in a single sentence, but just right for a couple of
tables.
Table
6.2 lists the information carried in general component and window
events. For these events, the result of the event is largely
independent of the class of the target object. A key-press event,
for example, conveys the time, key, and modifier status of the
event, regardless of whether the key press was received by a text
field, a button, or some other component.
Table
6.2: Information in Component and Window Events—JDK 1.0.2
| Kind
of event |
Target
class |
Event
ID and valid fields |
| Keyboard |
Component |
KEY_PRESS:
when, key, modifiers |
KEY_RELEASE:
when, key, modifiers |
KEY_ACTION:
when, key, modifiers |
KEY_ACTION_RELEASE:
when, key, modifiers |
| Mouse |
Component |
MOUSE_DOWN:
when, x, y, modifiers, clickCount |
MOUSE_UP:
when, x, y, modifiers |
MOUSE_MOVE:
when, x, y, modifiers |
MOUSE_DRAG:
when, x, y, modifiers |
MOUSE_ENTER:
when, x, y |
MOUSE_EXIT:
when, x, y |
Window |
Window |
WINDOW_DESTROY |
WINDOW_ICONIFY |
WINDOW_DEICONIFY |
Dialog |
WINDOW_MOVED:
x, y |
Frame |
WINDOW_MOVED:
x, y |
| Focus |
Component |
GOT_FOCUS |
LOST_FOCUS |
Table
6.3 presents action and action-like events. These are events that
convey the result of a user action in cases where the result
depends very much on the class of the target object . For example,
pressing on a button generates an action event conveying the
string label of the button. Action and action-like events use the
generic arg field to carry this variable information.
Table
6.3: Information in Action and Action-like Events—JDK 1.0.2
| Kind
of event |
Target
class |
Event
ID and valid fields |
| Action |
Button |
ACTION_EVENT:
arg = target.getLabel() |
Checkbox |
ACTION_EVENT:
arg = new Boolean(state) |
Choice |
ACTION_EVENT:
arg = target.getItem(index) |
List |
ACTION_EVENT:
arg = target.getItem(index) |
TextField |
ACTION_EVENT:
arg = target.getText() |
MenuItem |
ACTION_EVENT:
when, modifiers, arg = target.getLabel() |
| Action-like |
List |
LIST_SELECT:
arg = new Integer(index) |
LIST_DESELECT:
arg = new Integer(index) |
Scrollbar |
SCROLL_LINE_UP:
arg = new Integer(value), where value reflects the
scroll bar's new position |
SCROLL_LINE_DOWN:
arg = new Integer(value) |
SCROLL_PAGE_UP:
arg = new Integer(value) |
SCROLL_PAGE_DOWN:
arg = new Integer(value) |
SCROLL_ABSOLUTE:
arg = new Integer(value) |
The Event
class defines two further event types, Event.LOAD_FILE
and Event.SAVE_FILE, but these are not used by the JDK.
Note: Action and action-like
events are delivered to the AWT components only after the native
toolkit object (the peer) receives them. This means that before your
AWT component even has a chance to see the event, the peer object
has already performed some default event processing, such as showing
the button press for a button.
|
|
Q . What is the general model in the JDK 1.0.2 for distributing and handling events?
|
Ans :
The event
model in the JDK 1.0.2 propagates events up the containment
hierarchy and requires that you subclass a component to
capture and handle its events.
The
JDK 1.0.2 event model works well for small applets and
applications. It was designed to:
- promote native
look and feel by coordinating event handling between AWT
components and their native-platform peers.
- promote
extensibility and flexibility of AWT components by giving the
AWT programmer choices in how and where to handle events.
The
basic process for handling an event runs as follows. The native
windowing system receives the event (key press, mouse click, etc.)
and determines which peer component should receive it. The chosen
peer component converts the native event to an AWT Event
object and passes the event on by invoking the postEvent
method on its AWT counterpart.
The peer thus starts a chain of
event passing, all managed by Component's postEvent
method:
/* in Component.java (JDK 1.0.2): */
public boolean postEvent(Event e) {
ComponentPeer peer = this.peer;
if (handleEvent(e)) {
return true;
}
Component parent = this.parent;
if (parent != null) {
e.translate(x, y);
if (parent.postEvent(e)) {
return true;
}
}
if (peer != null) {
return peer.handleEvent(e);
}
return false;
}
The gist of this
code is to ascend the containment hierarchy recursively, looking
for a component that is willing to consume the event. The main
steps are as follows:
- The
handleEvent
method is invoked on the current component. If this method
returns true, the event is considered handled and
goes no further.
- If
handleEvent
returns false, and the component has a parent, postEvent
starts over with the parent.
- If repeating
steps 1 and 2 leads to a top-level window, which also returns
false
from handleEvent, the event is finally passed to
the peer of the original AWT component that started the upward
chain. The peer can then take some platform-specific default
action in response to the event, such as registering a key
press in a text field.
The JDK 1.0.2 event
model gives you three basic options when overriding an
event-handling method in some Component subclass:
- consume the
event by processing it and returning
true
- filter the event
by partially processing it and returning
false
- pass on the
event, untouched, by simply returning
false
(Returning false
is the default behavior inherited from class Component.)
The JDK 1.0.2 only partially
implements this model. Keyboard events are passed on to all AWT
components, but other events must occur in a Canvas, Panel,
Frame, or Window for the AWT to see
them.
Note: Text fields rely on
their native peers for parts of their functionality. Your TextField
subclass should therefore do whatever processing is necessary and
then return false so that the event eventually
reaches the text field's peer.
|
|
Q . What methods should I use in the JDK 1.0.2 to handle events?
|
Ans :
Use an
event-specific method, such as keyDown
or mouseDown, where possible;
otherwise use the all-purpose handleEvent
method.
The
Component class in the JDK 1.0.2 provides two kinds
of methods for handling events. There are several methods that
handle only specific events or event types, and one catch-all
method, as shown in Table 6.4.
Table
6.4: Methods for Handling Events—JDK 1.0.2
| Event-specific
methods |
action |
keyDown,
keyUp |
mouseDown,
mouseUp |
mouseMove,
mouseDrag |
mouseEnter,
mouseExit |
gotFocus,
lostFocus |
| Catch-all
method |
handleEvent |
Where
possible, you should use the more specific event-handling methods.
They often lead to simpler and clearer code. Instead of handling
all the events in one large, ungainly method, you can write
simple, separate methods for each of the event types your
application needs. The method names themselves indicate which
specific events your code is handling.
Overriding the handleEvent
method is unavoidable for some event types, such as Event.WINDOW_DESTROY,
because there is no specific method for catching them. If you
override handleEvent but still want access to the
event-specific methods, you must incorporate the superclass's
version of handleEvent as part of your own handleEvent
method:
/* using JDK 1.0.2: */
public boolean handleEvent(Event evt) {
if (evt.id == Event.WINDOW_DESTROY) {
// ... window destroy handler code goes here
return true;
} else {
return super.handleEvent(evt);
}
}
Including
the call to super.handleEvent accesses the version of
handleEvent defined in the Component
class. As can be seen from the following JDK 1.0.2 source code,
this method dispatches events to appropriate event-specific
methods where possible, or else it returns false,
indicating that the event is unhandled:
/* in Component.java (JDK 1.0.2) */
public boolean handleEvent(Event evt) {
switch (evt.id) {
case Event.MOUSE_ENTER:
return mouseEnter(evt, evt.x, evt.y);
case Event.MOUSE_EXIT:
return mouseExit(evt, evt.x, evt.y);
case Event.MOUSE_MOVE:
return mouseMove(evt, evt.x, evt.y);
case Event.MOUSE_DOWN:
return mouseDown(evt, evt.x, evt.y);
case Event.MOUSE_DRAG:
return mouseDrag(evt, evt.x, evt.y);
case Event.MOUSE_UP:
return mouseUp(evt, evt.x, evt.y);
case Event.KEY_PRESS:
case Event.KEY_ACTION:
return keyDown(evt, evt.key);
case Event.KEY_RELEASE:
case Event.KEY_ACTION_RELEASE:
return keyUp(evt, evt.key);
case Event.ACTION_EVENT:
return action(evt, evt.arg);
case Event.GOT_FOCUS:
return gotFocus(evt, evt.arg);
case Event.LOST_FOCUS:
return lostFocus(evt, evt.arg);
}
return false;
}
|
|
Q . What is an action event?
|
Ans :
An action
event is the way some AWT components notify your program that they
have been acted on and now have new information to report.
Table
6.5 shows the user-interface elements that generate action events
in the JDK 1.0.2.
Table
6.5: Components that Generate Action Events—JDK 1.0.2
| Component |
Generates
action event for ___ |
Button |
mouse
click |
Checkbox |
mouse
click |
Choice |
mouse
click |
MenuItem |
mouse
click |
List |
double
mouse click |
List |
return
key press |
TextField |
return
key press |
To
catch and process an action event, you need to define your own Component
subclass and override its action method. Remember to
return true from your action method if
you've handled it completely, or false if you want to
pass it on for further processing .
|
|
Q . How does the JDK 1.0.2 handle events for function keys, arrow keys, and so on?
|
Ans :
The JDK
1.0.2 delivers "action" key events like other key
events—in either a keyDown
or keyUp method—but the event id
field is set to KEY_ACTION or KEY_ACTION_RELEASE.
The
AWT has a broad category of action keys, which contains the
function keys 1-12 together with the navigation keys UP,
DOWN, LEFT, RIGHT, HOME,
END, PGUP, and PGDN. An
event generated by one of these keys will carry the information
shown in Table 6.6.
Table
6.5: Components that Generate Action Events—JDK 1.0.2
| Field |
Possible
value |
id |
Event.KEY_ACTION
or Event.KEY_ACTION_RELEASE |
key |
Event.F1,
Event.F2, ..., or Event.PGDN |
To
handle an action key event, you should override the keyDown
or keyUp method in your component subclass and check
that the event's id is KEY_ACTION or KEY_ACTION_RELEASE.
A common point of confusion about
the Event class is how to interpret and how to use
the public int class variables, such as Event.KEY_ACTION,
Event.F1, and Event.SHIFT_MASK. Only some
of these variables represent different event types. The rest,
listed in Table 6.7, represent key types and key modifier bit
masks.
Table
6.7: public int Class
Variables in the Event Class
that Are Not Event Types
Key
types for KEY_ACTION events |
F1,
F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12
HOME, END, PGUP, PGDN, UP, DOWN, LEFT, RIGHT |
| Bit
masks for key modifiers |
SHIFT_MASK,
CTRL_MASK, META_MASK, ALT_MASK |
If
you see source code in which one of these key types or bit masks
is compared to the event's id field, you know it's a
mistake.
|
|
Q . My frame doesn't close when I click on Quit/Close in the main menu-how do I fix this using JDK 1.0.2?
|
Ans :
Override handleEvent
to process the WINDOW_DESTROY event.
Clicking
on Quit/Close (depending on the native windowing system) generates
a window-destroy event in the JDK 1.0.2, which your application
needs to catch and handle appropriately. You use Frame's
dispose method to dispose of the frame along with any
resources connected to it. If you want the frame's
closing to terminate the application as well, you can invoke System's
exit method.
Besides frames, the WINDOW_DESTROY
event is also delivered to Dialog objects, which
might choose to hide rather than dispose of themselves.
In the JDK 1.0.2, you catch the
window-destroy event by subclassing Frame and
overriding its handleEvent method; for example:
/* using JDK 1.0.2: */
public boolean handleEvent(Event e) {
if (e.id == Event.WINDOW_DESTROY) {
dispose(); // or hide();
// Uncomment the following line to quit the application.
// System.exit(0);
return true;
} else {
return super.handleEvent(e);
}
}
|
|
Q .
How is my program notified when a menu item is selected?
|
Ans
:
A menu item
triggers an action event when it is selected; you need to catch
and handle the event in the Frame object (that is,
top-level window) containing the menu.
Menu
items trigger action events, but their system for propagating and
handling events is different from that used by regular components.
Menu items (instances of the MenuItem class or its
subclasses, including Menu) function as distant
step-cousins of components—the two sides aren't really related,
but for limited purposes they behave as if they belong in the same
family. The MenuItem class inherits from MenuComponent
rather than Component, and MenuComponent
supports only a fraction of the functionality found in Component.
The differences that impact event handling are summarized in Table
6.8.
Table
6.8: Event Handling—Component
versus MenuComponent
Component |
MenuComponent |
Containment
hierarchy is based on
Component and Container
classes |
Containment
hierarchy is based on MenuComponent class
and MenuContainer interface |
| Provides
family of methods for handling events |
Provides
no methods for handling events |
postEvent
method checks for event handler before propagating event
up the component containment hierarchy |
postEvent
method always propagates event up the menu containment
hierarchy |
Thus, menu items
are event propagators but not event handlers. The action event
generated by a menu item must propagate to a nonmenu container
before it can be handled.
The AWT is designed to have each
menu containment hierarchy rooted in a Frame object. The Frame
class implements the MenuContainer interface, so that
menu components can invoke menu container methods on Frame
instances. In particular, invocations of postEvent,
which propagate a menu item's action event upward, eventually
reach the Frame object containing the whole menu
hierarchy. Once there, they trigger Frame's version
of postEvent (inherited from Component),
which checks for an event handler by invoking handleEvent,
which in turn invokes action . Thus, to handle the events
generated by menu item selections, you must define a Frame
subclass and override its action method to respond to the menu
item events that can be generated within its menu system. The
following code fragment shows the skeleton for this:
/* using JDK 1.0.2: */
import java.awt.*;
public class MyFrame extends Frame {
public MyFrame() {
// ... build up menu system and attach to frame
}
// ...
public boolean action(Event e, Object arg) {
if (e.target instanceof MenuItem) {
// ... determine which specific menu item was selected
// ... return true if you've handled the event
}
return super.action(e, arg);
}
}
|
|
Q . How is my program notified in the JDK 1.0.2 when a list item is selected or deselected?
|
Ans
:
Your
program receives a LIST_SELECT
or LIST_DESELECT event, which you
must catch in your own handleEvent
method.
Instead
of using the all-purpose action event, lists in the JDK 1.0.2 can
send two kinds of events to distinguish between selecting and
deselecting list items: Event.LIST_SELECT and Event.LIST_DESELECT.
The event also reports the index of the selected or deselected
item by means of its arg field.
The list events do not have a
specific handler method. To catch them, you must override handleEvent,
for example:
/* using JDK 1.0.2: */
public boolean handleEvent(Event evt) {
if (evt.id == Event.LIST_SELECT) {
// ... your event processing here
// ... evt.arg = index of newly selected item
return true;
} else if (evt.id == Event.LIST_DESELECT) {
// ... your event processing here
// ... evt.arg = index of newly deselected item
return true;
} else {
return super.handleEvent(evt);
}
}
|
|
Q . How do I hook up a scroll bar in the JDK 1.0.2 so that it controls the scrolling of some other component?
|
Ans
:
Capture the
scroll bar events in a handleEvent
method and use the scroll bar's changing position to control your
other component(s).
The
Scrollbar class in the JDK 1.0.2 provides the basic
support for controlling a slider on screen and for using the
slider's position to control other objects. It may help to think
of this class as providing a slider that has the potential for
controlling scrolling.
Scroll bars provide five different
ways of adjusting the value that the scroll bar represents: move
forward by a small or large amount, move backward by a small or
large amount, or move as dragged by the mouse. Each of these is
expressed by a distinct constant in the Event class,
as shown in Table 6.9.
Table
6.9: id Constants in Class Event
for Scrollbar Event Types
SCROLL_LINE_DOWN |
move
forward (right/down) by one unit |
SCROLL_PAGE_DOWN |
move
forward (right/down) by one page |
SCROLL_LINE_UP |
move
backward (left/up) by one unit |
SCROLL_PAGE_UP |
move
backward (left/up) by one page |
SCROLL_ABSOLUTE |
move
to track mouse as it drags scroll bar knob |
When
a scroll event occurs, the Event object's id
field will indicate which of the five types it was. (You can think
of scroll bar events as a kind of action event that comes in five
flavors.)
To use a scroll bar, you need to add
it to a container and use its changing position to control some
other object. When a scroll bar is moved, it sends out scroll-type
events with information about the scroll bar's new position. To
catch the event, you must override the handleEvent
method in a Scrollbar subclass or in a parent of the
scroll bar. For example:
/* using JDK 1.0.2: */
public boolean handleEvent(Event e) {
if (e.target instanceof Scrollbar) {
switch(e.id) {
case Event.SCROLL_LINE_DOWN:
// ... your event processing here
// ... e.arg = new position (value) of scroll bar
// ... return true if you've handled the event
break;
case Event.SCROLL_PAGE_DOWN:
// ...
break;
// ... handle other scroll types
}
}
return super.handleEvent(e);
}
The
JDK 1.1 greatly simplifies scrolling for the developer by
providing the ScrollPane class with built-in
connections to manage scrolling.
|
|
Q .
Does the AWT in the JDK 1.0.2 distin
guish between mouse clicks made with different buttons on a two- or three-button mouse?
|
Ans
:
Yes; it
makes the extra distinction by using the Event
object's modifiers field.
All
mouse clicks generate mouse-down and mouse-up events, but you can
inspect the modifiers field in the Event
object to determine which button was pressed. The JDK 1.0.2 uses
the mapping shown in Table 6.10.
modifiers
Field in Mouse Clicks—JDK 1.0.2
| If
___ mouse button click |
then
mouse event + ____ |
| left |
no
modifier |
| right |
meta
key |
| center |
alt
key |
The
Event class provides a metaDown method
to test the status of the meta key, but regrettably, no
corresponding altDown method exists in the JDK 1.0.2.
(The JDK 1.1 has regularized the modifier access methods; see
Q7.14.) Therefore, you have to explicitly use the ALT_MASK
bit mask provided by the Event class to test the
event's modifiers field. For example:
/* using JDK 1.0.2: */
public boolean mouseDown(Event e, int x, int y) {
if (e.modifiers == 0) {
// ... handle plain (left) mouse click
return true;
}
if (e.metaDown()) {
// ... handle right mouse click
return true;
}
if ((e.modifiers & Event.ALT_MASK) != 0) {
// ... handle center mouse click
return true;
}
return super.mouseDown(e, x, y); // a good default response
}
|
|
|
|