Chapter 21

Event Handling


CONTENTS


Many of the actions that take place in the Java environment occur as events that can be handled programmatically. This chapter focuses on the types of events supported by Java, along with how to write code that responds to them. In this chapter, you learn how to handle events such as key presses on the keyboard, mouse movements and button clicks, and some more abstract events that aren't directly related to user input. You also learn about the internal makeup of the Java system that enables event processing.

Event-Driven Programming

Java is an event-driven environment, meaning that most actions that take place in Java generate an event that can be handled and responded to. In Java, an event is defined quite literally as something that happens that you might want to know about. For example, when a Java component gains the input focus, an event occurs because it might be important for your applet to know about the focus change.

In the event-driven world of Java, the flow of your program follows events external to your applet, as opposed to following an internally linear program flow. This is an important point, because it means that a Java applet is in a constant state of responding to events. The most visible events are things like mouse clicks and key presses, which are known as input events. You provide methods that respond to these events, which are called event handlers. Figure 21.1 shows how program flow is altered by external events.

Figure 21.1: How external events impact program flow.

Because of the inherent graphical nature of Java applets, it will eventually become obvious to you why the event-driven programming model is not only more convenient, but downright necessary. With the potential of having multiple applets on a single Web page, along with on-the-fly system configuration changes and a multitude of other things going on, a procedural programming model would be much more difficult to manage. The event-based model provides a more sound solution to the problems inherent in a system with a graphical interface, such as Java.

All events in Java are processed within the java.awt (Advanced Windowing Toolkit) package, and are tightly linked to AWT components. A component is basically a generic abstraction for a Java window. If you recall, Java applets are themselves a specific type of component. This means that they inherit the same event-processing features built in to the Component superclass. For more juicy details on the Component class and the AWT package, refer to Chapter 28, "Package java.awt."

AWT Event Handling

The Java AWT is responsible for generating events in response to user actions. For example, when the user selects a button, an event of type ACTION_EVENT is generated. These events are in turn processed by applications or applets, who use the AWT to respond to the events in an event-driven manner.

Somewhere deep inside the AWT is an event-processing loop, which handles the dirty job of routing events to their appropriate targets. This process of routing an event to a target object is known as posting an event. It should come as no surprise that the method used to post events to target objects is the postEvent method, which is defined for all target objects. For target objects derived from Component, postEvent will in turn call the handleEvent method. handleEvent serves as the default handler for all events, and it has the option of responding to an event or letting it pass through. If handleEvent doesn't handle an event, it returns false, in which case the parent object's handleEvent method is called. This process continues until an event is handled or the top of the object tree is reached. Figure 21.2 shows how this event-handling process takes place.

Figure 21.2: The Java AWT eventhandling process.

The Java AWT provides a class for encapsulating all types of events that can occur within the system: Event. The Event class models a generic event and has constants defined within it to represent specific events. You learn more details about the Event class a little later in this chapter. The Event class is used primarily by the handleEvent method, which is defined as:

public boolean handleEvent(Event evt)

Notice that handleEvent takes an Event object as its only parameter. handleEvent uses this Event object to determine what type of event has occurred. It then calls a more specific event-handler method to deal with the specific event. For example, if a key is pressed, the Event object's id member variable is set to KEY_PRESS, which is a constant defining the key press event. handleEvent checks the value of id and upon finding it equal to KEY_PRESS, calls the keyDown handler method. Following is a section of code showing the keypress-handling portion of the handleEvent method in the 1.02 release of Java:

public boolean handleEvent(Event evt) {
  switch (evt.id) {
    ...
  case Event.KEY_PRESS:
    return keyDown(evt, evt.key);
    ...
  }
  return false;
}

The handling of other system events is very similar to that of the KEY_PRESS event. You could easily override handleEvent to provide custom routing of event handlers, but it is rarely necessary. Although you may not ever need to intervene with the default event-handling provided by handleEvent, it is nevertheless important to understand how it works.

The Event Class

The Event class is a critical component of the Java AWT. Event objects are constructed and passed into methods such as postEvent when an event occurs. They then are used in handleEvent and other methods to encapsulate the specifics regarding a particular event. A thorough understanding of the Event class is important for the successful handling of events generated by the AWT.

Member Variables

The Event class defines a lot of member constants that represent a variety of event types and states, which you learn about in the next section. Beyond these constants, there are also member variables defined in Event that are used to store the state of a particular event. These member variables follow:

Object  target;
long    when;
int     id;
int     x;
int     y;
int     key;
int     modifiers;
int     clickCount;
Object  arg;
Event   evt;

The target variable specifies the object in which the event occurred; for example, in the case of a button press event, the target variable would contain the associated Button object. The when variable is a timestamp for the event, which specifies exactly when the event occurred. The id variable is used to store the type of event that occurred; you learn more about event types in the next section. The x and y variables are the coordinates of the event within the target graphical object. A typical usage of x and y is keeping up with the mouse position when an event occurs.

The key and modifiers variables are used for storing extra information related to keyboard input events. The clickCount variable keeps up with the number of consecutive mouse clicks, and it is only applicable to mouse events. The arg variable is a generic storage member for associating arbitrary information with an event. Finally, the evt variable is used to store the next Event object when building a linked list of events.

Types

The Event class defines a set of constants, which specify the different types of possible events (see Table 21.1). These event constants are pretty self-explanatory in that their name sufficiently describes the type of event they represent.

Table 21.1. Constant event types defined in the Event class.

ACTION_EVENT   
    
GOT_FOCUS LOST_FOCUS  
    
KEY_ACTION KEY_ACTION_RELEASE KEY_PRESS
KEY_RELEASE   
    
LIST_DESELECT LIST_SELECT  
    
LOAD_FILE SAVE_FILE  
    
MOUSE_DOWN MOUSE_DRAG MOUSE_ENTER
MOUSE_EXIT MOUSE_MOVE MOUSE_UP
    
SCROLL_ABSOLUTE SCROLL_LINE_DOWN SCROLL_LINE_UP
SCROLL_PAGE_DOWN SCROLL_PAGE_UP  
    
WINDOW_DEICONIFY WINDOW_DESTROY WINDOW_EXPOSE
WINDOW_ICONIFY WINDOW_MOVED  

Usage

The id field is used by the AWT (and possibly your own Java code) to distinguish between event types. The information associated with an event varies depending on the type of event. For example, the MOUSE_DOWN event type is generated when a mouse button is pressed. Because the coordinates of the mouse often are used when handling a mouse button-click event, the x and y member variables of Event are filled in with the current mouse coordinates.

Some event information is meaningless in the context of other types of events, so it's important to understand which member variables of the Event class are valid in particular circumstances. Table 21.2 lists the member variables of the Event class that are valid for each different type of event. Keep in mind that the target and id variables are valid for every type. Also, some event types are never generated by the AWT, so their valid variables are all unknown.

Table 21.2. Valid member variables for different events.

EventValid Fields
ACTION_EVENT arg*
LIST_DESELECT arg
LIST_SELECT arg
GOT_FOCUS none
LOST_FOCUS none
LOAD_FILE never generated
SAVE_FILE never generated
MOUSE_DOWN when, x, y, modifiers, clickCount
MOUSE_DRAG when, x, y, modifiers
MOUSE_ENTER when, x, y
MOUSE_EXIT when, x, y
MOUSE_MOVE when, x, y, modifiers
MOUSE_UP when, x, y, modifiers
SCROLL_ABSOLUTE arg
SCROLL_LINE_DOWN arg
SCROLL_LINE_UP arg
SCROLL_PAGE_DOWN arg
SCROLL_PAGE_UP arg
KEY_ACTION when, x, y, key, modifiers
KEY_ACTION_RELEASE when, x, y, key, modifiers
KEY_PRESS when, x, y, key, modifiers
KEY_RELEASE when, x, y, key, modifiers
WINDOW_DEICONIFY none
WINDOW_DESTROY none
WINDOW_EXPOSE never generated
WINDOW_ICONIFY none
WINDOW_MOVED x, y
(* For MenuItem and CheckboxMenuItem objects, the fields when and modifiers are also valid. Also keep in mind that the target and id variables are valid for all events.)

Java Input Events

As you've learned throughout the chapter, user input in Java is handled through an event-driven architecture. When the user interacts with an input device, it results in an input event being dispatched to the component with the input focus. In most cases, this component is the applet window. An input event is a special type of event that notifies an applet that something has occurred on an input device. An example of an input event is a movement of the mouse.

Input events are crucial in Java programs because they provide a means of handling user responses. If Java applets could not monitor user responses, they wouldn't be very interactive, which is one of the primary benefits of Java applets. Java user event responses come in two varieties, which correspond to the input devices supported by Java. The two types of input events supported in the current release of Java follow:

Keyboard events are events generated by a key press on the keyboard. Whenever the user presses a key, a keyboard event is generated that can be trapped and handled by the applet with the input focus. Actually, a key press generates two events, a key down event and a key up event. You'll learn more about these two types in a moment.

Mouse events are generated by mouse clicks and movements. Every mouse click and mouse movement generates a corresponding mouse input event. Like key presses, mouse clicks actually come as a series of events; a mouse-click down event and a mouse-click up event. There is also a mouse event specifically targeted at mouse dragging. Mouse dragging occurs when the mouse is moved with the button down. Applets wanting to respond to mouse clicks and movement simply have to process these events and take action accordingly. You learn more about processing mouse events a little later in this chapter.

Note
You may have noticed in the discussion of mouse events the mention of the mouse button, as opposed to the mouse buttons. This is intentional because Java only supports a single mouse button. This may seem limiting to users on some platforms, such as Windows, but keep in mind that Java is designed to support as many platforms as possible. Considering the fact that some platforms have mice with a single button, such as Macintosh, it makes sense for Java to support only a single button.

Keyboard Events

Java keyboard events are generated when the user presses or releases a key. There are two standard keyboard event-handler methods supported by the Component class: keyDown and keyUp. These two methods are defined as:

public boolean keyDown(Event evt, int key)
public boolean keyUp(Event evt, int key)

The keyDown method is called in response to the user pressing a key, and the keyUp method is called in response to the user releasing a key. Both methods are passed an Event object and an integer key value parameter. The key value parameter, key, specifies which key was pressed or released. The Event object parameter contains extra information relating to the keyboard event, such as whether the Shift key was held down when the key was pressed.

The Event object contains constants representing the different keys that can be specified in the key parameter. Table 21.3 shows a list of some of the more useful key constants.

Table 21.3. Useful key constants.

ConstantKey
UP Up arrow
DOWN Down arrow
LEFT Left arrow
RIGHT Right arrow
HOME Home
END End
PGUP Page Up
PGDN Page Down

To check if the key pressed or released is one of these keys, you override keyDown or keyUp and compare the value of key to one of the constants. Following is an example of overriding keyDown to check for the user pressing one of the arrow keys:

public boolean keyDown(Event evt, int key) {
  switch (key) {
  case Event.LEFT:
    // left arrow key pressed
    break;
  case Event.RIGHT:
    // right arrow key pressed
    break;
  case Event.UP:
    // up arrow key pressed
    break;
  case Event.DOWN:
    // down arrow key pressed
    break;
  }
  return true;
}

This code shows that handling different key presses is as easy as providing a switch statement with case clauses for each key. Although the example here used the keyDown method for handling key presses, the keyUp method works in the same fashion.

If you need more details about the key that was pressed or released, you can use the Event object passed into the keyDown and keyUp methods. The typical usage of the Event object in regard to key processing is to check for modifier keys. Modifier keys are keys that can be pressed in conjunction with other input events, such as the Shift and Control keys. The three methods in Event used to check the status of modifier keys follow:

public boolean shiftDown()
public boolean controlDown()
public boolean metaDown()

All these methods return Boolean values specifying whether or not the key in question is being held down. Checking the status of the modifier keys is necessary sometimes in applets that make heavy use of the mouse. For example, you may have a drawing applet that performs a different function if the Shift key is held down and the mouse is moved.

Note
The shiftDown, controlDown, and metaDown methods actually check for the flags SHIFT_MASK, CTRL_MASK, and META_MASK, which are defined in the Event class. You can check for any of these flags yourself in lieu of using the comparable methods. There is also an ALT_MASK flag which specifies that the Alt key was pressed.

Mouse Events

Mouse events occur when the user moves the mouse or clicks the mouse button. There are a handful of methods for handling mouse events. These methods follow:

public boolean mouseUp(Event evt, int x, int y)
public boolean mouseDown(Event evt, int x, int y)
public boolean mouseMove(Event evt, int x, int y)
public boolean mouseDrag(Event evt, int x, int y)
public boolean mouseEnter(Event evt, int x, int y)
public boolean mouseExit(Event evt, int x, int y)

All these methods are passed an Event object and two integer parameters representing the X and Y position of the mouse pointer. The mouseUp and mouseDown methods are called when the user presses and releases the mouse button. The mouseMove method is called when the mouse is moved. The mouseDrag method is very similar to the mouseMove method; the only difference is that mouseDrag is called when the mouse is moved with the button held down. The mouseEnter and mouseExit methods are used to track when the mouse enters and exits the applet window.

You can use the x and y parameters passed into the mouse event handler methods to perform any processing based on the position of the mouse. The following code snippet contains an example of overriding the mouseMove method to output the mouse position to standard output:

public boolean mouseMove(Event evt, int x, int y) {
  System.out.println("Mouse position = (" + x + ", " + y + ")");
  return true;
}

Similar to the keyboard event handlers, you can use the Event object passed in the mouse event handlers to find out additional information such as the status of modifier keys.

Summary

In this chapter, you learned about Java events and the event-driven architecture necessary to support them. More specifically, you learned about Java input events, including the input devices capable of generating them and how they are handled by the Java AWT library. You saw examples of using the input event-handler methods to capture and respond to keyboard and mouse events.