Java 1.1 Event Handling - DRAFT 15/2/96

Introduction

Graphical User Interface systems handle user interaction using an event driven model. That is, the user performs an action such as moving the mouse, pressing a key or releasing one, etc. These all generate events of some kind. A GUI system such as the Java AWT, Microsoft Windows, Motif, or any other windowing system will sit in an event loop waiting for these events to occur. When one does, application code is called in some way to respond to the event.

The way in which application code is called varies between the different windowing systems. In some, the application programmer has to write an event loop handler themselves, and when an event occurs the application has to figure out what to do with it. In other systems some assistance may be given with this, where events are dispatched to graphical objects automatically. When they arrive, application code still has to work out what type of event has occurred. In yet other systems, the application merely needs to register an event handler with an object, and the handler will be called whenever the right event occurs in the right object, without any further need for intervention by the application programmer.

Java in release 1.1 is now up to its third event processing model! The first one - called the ``old'' event model was abandoned before Java left beta stage. It was replaced by the ``new'' event model for Java 1.0. Unfortunately, two things marred this transition to the new model:

The difference between the old and new models is subtle and depends on a complex interplay of events that belong to the underlying native implementation and the Java events. This was covered in the Java 1.0 version of this book.

Both the old and new models had serious Software Engineering deficiences that led to poor quality code as soon as applications started to grow in scale. A solution to this was already known as the Command Pattern, and this was adopted for the third event model for the Java AWT. The Command Pattern was renamed ``delegation'' by Sun engineers, and forms a much cleaner way of handling events. Basically, it allows the application to register handlers (called listeners) with graphical objects, which are called when suitable events arrive.

There are complex implementation layers and issues arising from the third event model. When the user performs an action such as a keypress, a native code event is generated. This is firstly handled by native code at, say, the Windows or X level. The event may be caught by the native toolkit or ignored. If caught, two things may happen:

Which one of these occurs depends on the event type.

When an event is handed to the Java layer, it is changed into a Java event. Java code looks to see if there is an event listener using the third event model. If there is, this is used. If there is not, then the second ``new'' event model is used. Sometimes there is no listener but the third model should be used anyway. This can be forced.

If all this sounds grim, then be reassured: if you only want to do simple things, the delegation event model lets you do them simply. Most of the time you only want to simple things.

Listeners

A listener is registered with an event type for an object. For example, an application can register a key event listener for any Component, or an action event listener for objects such as Button or TextField. Listeners are where the programmer places application specific code to respond to user events. When a suitable event occurs, an appropriate method on the listener is invoked.

For example, suppose we are building a Web browser. We may have a Back button to return to the previously displayed page. When we click on this Back button, the application will need to reload the last page into the browser window and reset history lists, current URL pointers, etc. This is not GUI code, though it is clearly application code that affects GUI objects as well as other application objects of the browser. The Back function can also be invoked in other ways, such as by a hot-key or by menu selection. Not only is the behavior application specific, but there is more than one way way of invoking this behavior. A listener object encapsulates this behavior, and should be registered with the Back button, the hot-key combination and the menu selection.

When a listener is invoked, it has to be by one of its methods. There could be a standard method such as execute() or by one customised to the event that caused it. The JDK 1.1 has chosen the second method. So if the mouse is clicked in a Button, then an action event is generated (invisibly to most applications), and the actionPerformed() method is called on any action listener. On the other hand, whenever a key is pressed in a Component, then the method keyPressed() is called in any key event listener.

This could have been more simply if simplicity was the only driving force behind this event model: however, Java Beans imposes extra requirements which lead to these multiple event types.

The methods defined for listeners are done using interfaces. This is an absolutely appropriate use of the interface mechanism. Since listeners contain application code, they will probably have an inheritance based on the application, not on some vagaries of the GUI side. All the listener needs to do is to implement certain methods, so that the internal event handling code can call the right method. So, for example, the ActionListener is defined by

  public interface ActionListener extends EventListener {
      public abstract void actionPerformed(ActionEvent e)
  }
whereas KeyListener is defined by
  public interface KeyListener extends EventListener {
      public abstract void keyPressed(KeyEvent e);
      public abstract void keyReleased(KeyEvent e);
      public abstract void keyTyped(KeyEvent e);
  }

Implementing Listeners

Since a listener is defined as an interface, any application code inheriting a listener specification must implement its methods. The rest of the listener code is upto the application. Listener methods will usually interact with other objects of the application. Some of these will be GUI objects, some won't. It doesn't really matter. Returning to our browser example, the Back button listener will need to access the URL object to retrieve the previous URL, and the browser display object to show it. One is graphical, the other is not.

Listener objects - just like any object - get knowledge about other objects in three ways

Here is a trivial application just to show how listeners are created and used. The application has a Button on the left, a Button on the right and a Label in the middle. The left Button has the label ``Left'', and the right one has the label ``Right'' When either Button is pressed, the text showing in the Label is set to either ``Left'' or ``Right'' i.e. the label of the Button pressed.

import java.awt.Button;
import java.awt.Label;
import java.awt.event.ActionListener;

/**
 * This application consists of two Buttons with a Label
 * between them. When a Button is pressed, its text is
 * set in the Label
 *
 * @author Jan Newmarch
 */
public class DelegateDemo extends Frame {

    public static void main(String argv[]) {
	new SimpleEvent().show();
    }

    public DelegateDemo() {
	// create the GUI objects
	Button left = new Button("Left");
	Button right = new Button("Right");
	Label label = new Label("Center");

	// set their geometry
	add(left, "West");
	add(right, "East");
	add(label, "Center");
	pack();

	// create a listener and add it to each Button
	SimpleListener simple = new SetText(label);
	left.addActionListener(simple);
	right.addActionListener(simple);	
    }
}

/**
 * A listener object that is invokded when a Button is activated
 * It finds the Button's label and sets it in a Label
 */
class SetText implements ActionListener {

    private Label label;

    public SetText(Label l) {
	// the listener needs to know the Label it will act on 
	label = l;
    }

    public void actionPerformed(java.awt.event.ActionEvent e) {
	// get the label showing in whichever Button was pressed
	String name = e.getActionCommand();

	// set this in the Label object
	label.setText(name);
    }
}	

AWTEvent

Events that are handled by delegation objects are all subclassed from AWTEvent. If you are familiar with the old or new event models, then you will have used the Event class in your event handling code. Forget about that class now. It is superceded by AWTEvent. Forget also about all the fields and values that are present in Event - they are all absent from AWTEvent. The class AWTEvent has only one field, id, and that is protected anyway. The AWTEvent is very simple, and you don't even need to look at it unless you are doing arcane things (which we will do later).

For each type of event that is present in the delegation model, there is a separate class. The classes are divided into two types: low-level input or window events that every GUI object receives, and higher-level semantic events that only have meaning for particular GUI objects. In addition there are low-level window events that are only received by Frame and Dialog. This kind of division of types is not captured anywhere in the language, rather it is a guide to the programmer.

The low-level events for any Component are
Table 1: Low-level Event Types
Class id
ComponentEvent COMPONENT_MOVED
COMPONENT_RESIZED
COMPONENT_SHOWN
COMPONENT_HIDDEN
FocusEvent FOCUS_GAINED
FOCUS_LOST
KeyEvent KEY_PRESSED
KEY_RELEASED
KEY_TYPED
MouseEvent MOUSE_CLICKED
MOUSE_DRAGGED
MOUSE_ENTERED
MOUSE_EXITED
MOUSE_MOVED
MOUSE_PRESSED
MOUSE_RELEASED

Where are PaintEvent.PAINT etc?

The low-level window events for Frame and Dialog are
Table 2: Low-level Window Event Types
Class id
WindowEvent WINDOW_CLOSED
WINDOW_CLOSING
WINDOW_DEICONIFIED
WINDOW_ICONIFIED
WINDOW_OPENED

The semantic level events are
Table 3: Semantic Event Types
Class id
ActionEvent ACTION_PERFORMED
AdjustmentEvent ADJUST_VALUE_CHANGED
ItemEvent ITEM_STATE_CHANGED

For the low-level events, the protected id takes on different values to distinguish between the type of event. This value can be found from the event method getId(). For the semantic level events, there is only one value for id, so that although getId() will give a value, it isn't really very useful (unless you have subclassed one of these semantic events and have your own extra id values). These values are used by the AWT to call appropriate methods on listeners, and you do not usually need to look at these values.

The semantic events are generated by the following
Table 3: Semantic Event Generation
Event Object Action
ActionEvent Button Click on Button
List Double-click on an item
MenuItem Click on MenuItem
TextField Press <Enter> key
AdjustmentEvent Scrollbar Any Scrollbar action
ItemEvent Choice Select an item
List Select or deselect an item
Checkbox ???
CheckboxMenuItem ???

Listeners for Different Events

For each event type that can occur, the application can add event listeners, that have methods invoked when the event occurs. The listeners are defined as interfaces, so that an actual listener has to implement these methods. The names of the listener classes are simply derived from the names of the events they handle, except that MouseEvent's have two different types of listener for efficiency reasons.
Table 4: Listeners for Each Event
Event Listener Method
ActionEvent ActionListener actionPerformed()
AdjustmentEvent AdjustmentListener adjustmentValueChanged()
ComponentEvent ComponentListener componentResized()
componentMoved()
componentShown()
componentHidden()
FocusEvent FocusListener focusGained()
focusLost()
ItemEvent ItemListener itemStateChanged()
KeyEvent KeyListener keyTyped()
keyPressed()
keyReleased()
MouseEvent MouseListener mouseClicked()
mouseEntered()
mouseExited()
mousePressed()
mouseReleased()
MouseMotionListener mouseDragged()
mouseMoved()
WindowEvent WindowListener windowClosed()
windowClosing()
windowDeiconified()
windowIconified()
windowOpened()

The elements of this table should be interpreted as follows:

Registering Listeners

A listener implements one of the interfaces ActionListener, AdjustmentListener, etc. Once created, listeners are registered with GUI objects. Of course, the GUI object has to be capable of generating the right type of event for the listener. Listeners are added to each object by a suitable add<event>Listener() call. In the simple example we had earlier, this was done for an ActionEvent listener on a Button by
    SimpleListener simple = new SimpleListener(label);
    left.addActionListener(simple);

The following table lists which objects can have which listener types added:
Table 5: Objects and Listeners for Them
GUI Object Listener
Button ActionListener
Choice ItemListener
Checkbox ItemListener
Component ComponentListener
FocusListener
KeyListener
MouseListener
MouseMotionListener
Dialog WindowListener
Frame WindowListener
List ActionListener
ItemListener
MenuItem ActionListener
Scrollbar AdjustmentListener
TextField ActionListener
Note that every GUI object inherits from Component. So every object can have Component, Focus, Key, Mouse and MouseMotion listeners added.

The next sections look at each event type in turn.

Action Events

Action events are generated for the following objects:
Table 6: Objects generating Action Events
GUI Object Action
Button Click on Button
List Double-click on an item
MenuItem Click on MenuItem
TextField Press <Enter> key

An ActionListener can be registered with each of these objects, and its method actionPerformed() is called when the user performs the indicated activity.

An ActionEvent has two methods that the programmer may find to be of use:

    public String getActionCommand()
    public int getModifiers()
Each ActionEvent carries around an ``action command''. This command may be set by the Button or MenuItem by their setActionCommand(String) method. There is no such method for List or TextField. The value of the action command (unless reset) is
Table 7: Value of Action Command
GUI Object action command
Button label
List ???
MenuItem label
TextField ???

The action command gives runtime information about the context in which the event occurred. This is semantic-level information, rather than low-level information: the text showing in the Button is usually enough useful information. If low-level information is required, the source object can be obtained from the method getSource() (or equivalent methods). This method is inherited by every event from the superior class java.util.EventObject.

We shall illustrate use of action events by four programs which do basically the same thing, but use different GUI elements to do this. The common part of these will be a Label which can have its foreground color set to different values. The color can be selected in different ways for each program, but they will all invoke the same ActionListener. This ActionListener is defined by the following:

import java.awt.Component;
import java.awt.Color;
import java.awt.event.ActionListener;

/**
 * An ActionListener that changes the foreground
 * color of a component passed in by the constructor
 *
 * @author Jan Newmarch
 */
public class SetColor implements ActionListener {
    final Color colors[] = {Color.red, Color.blue, Color.green};
    final String colorLabels[] = {"red", "blue", "green"};
    private Component comp;

    public SetColor(Component c) {
	comp = c;
    }

    /**
     * Invoked by an action event somewhere
     * resets the foreground of a component passed
     * in to the constructor
     */
    public void actionPerformed(ActionEvent e) {
	String colorName = e.getActionCommand();

        // search for Color matching color name
        for (n = 0; n < colorLabels.length; n++) {
            if (colorLabels[n].equals(colorName)) {
		// found a match, set foreground
                comp.setForeground(colors[n]);
		return;
            }
        }
	System.out.println("Unknown color: " + colorName);
    }
}

The first program to use this has a row of three buttons along the top and a label to below them. A single SetColor listener will be created and registered with each button. The application looks like

The code is

import java.awt.*;
import SetColor;

public class ButtonColor extends Frame {

    public static void main(String argv[]) {
	new ButtonColor().show();
    }

    public ButtonColor() {
	// the label that will be colored
	Label label = new Label("Click on button to change color");
	// a panel to hold the buttons
	Panel panel = new Panel();
	// buttons for each color
	Button red = new Button("red");
	Button blue = new Button("blue");
	Button green = new Button("green");

	// set geometry
	panel.setLayout(new FlowLayout());
	panel.add(red);
	panel.add(blue);
	panel.add(green);

	add(panel, "North");
	add(label, "Center");
	pack();

	// add the listener
	SetColor sc = new SetColor(label);
	red.addActionListener(sc);
	blue.addActionListener(sc);
	green.addActionListener(sc);
    }
}
The second program to use the SetColor listener will just change elements of the user interface. That is, instead of a set of buttons, it will use a list to the left of the label. In this version we shall only implement the double-click action, leaving single-click till later (that uses a different type of event). The application looks like

The code is
import java.awt.*;
import SetColor;

public class ListColor extends Frame {

    public static void main(String argv[]) {
	new ListColor().show();
    }

    public ListColor() {
	// the label that will be colored
	Label label = new Label("Double-click to change color");
	// the list of colors
	List colors = new List(3);
	colors.add("red");
	colors.add("blue");
	colors.add("green");

	// set geometry
	add(colors, "West");
	add(label, "Center");
	pack();

	// add the listener
	SetColor sc = new SetColor(label);
	colors.addActionListener(sc);
    }
}
Note that we have not changed the application code at all, only the GUI code. In this we are partly lucky since we are handling the same event type in both programs, but even handling different types does not cause many changes.

The third program will make the same kind of change. This time we shall use a menu of colors to make the selection. Each item in the menu will have the same listener added, just as for the buttons in the first program. The application looks like

The code is

import java.awt.*;
import SetColor;

public class MenuColor extends Frame {

    public static void main(String argv[]) {
	new MenuColor().show();
    }

    public MenuColor() {
	// the label that will be colored
	Label label = new Label("Select color from menu");

	// the menu bar
        MenuBar mb = new MenuBar();
        Menu color = new Menu("Color");
        mb.add(color);

	// menu color items
        MenuItem red = new MenuItem("red");
        MenuItem blue = new MenuItem("blue");
        MenuItem green = new MenuItem("green");

	color.add(red);
	color.add(blue);
	color.add(green);

	// set the geometry
	setMenuBar(mb);
	add(label, "Center");
	pack();

	// add the listener
	SetColor sc = new SetColor(label);
	red.addActionListener(sc);
	blue.addActionListener(sc);
	green.addActionListener(sc);
    }
}
Again there is no change to the application code.

The last example gives the last variation on this theme, using a TextField for color selection. The application looks like

The code is

import java.awt.*;
import SetColor;

public class TextFieldColor extends Frame {

    public static void main(String argv[]) {
	new TextFieldColor().show();
    }

    public TextFieldColor() {
	// the label that will be colored
	Label label = new Label("Enter color in the TextField");
	// the text field to enter the color
	TextField text = new TextField(20);

	// set geometry
	add(text, "North");
	add(label, "Center");
	pack();

	// add the listener
	SetColor sc = new SetColor(label);
	text.addActionListener(sc);
    }
}

This last piece of code is rather lacking in ease of use, as it gives no clues as to what are allowable text values!

Adjustment Events

Adjustment events are only generated for objects of class Scrollbar in Java 1.1. There is not so much need to use this class in Java 1.1, as there is also a ScrollPane class which looks after most details of handling a viewport onto a component.

A listener of class AdjustmentListener is added to a Scrollbar by the method

   public void addAdjustmentListener(AdjustmentListener)
The user can interact with the scrollbar by clicking the mouse within it, by dragging the slider or by keyboard interaction such as the arrow keys or PageUp/PageDown keys. These all cause the method
    public void adjustmentValueChanged(AdjustmentEvent)
to be called in the listener.

There is only the one method called despite the variety of ways that the user can interact with the scrollbar. If the application needs to distinguish between these, it can call the method getAdjustmentType() on the AdjustmentEvent. This will return one of the four values

The actual value of the scrollbar can be found from the method getValue() of the AdjustmentEvent. To use this value, you need to know where on the scale from minimum to maximum it occurs. These - and much other information - are available from the event of class Adjustable in which the event occurred (right now we know this is a Scrollbar but it could be other things in the future - for example, a Scale object).

Component Events

Most applications will not need to use events of type ComponentEvent. This is used for tracking movement, resizing and visibility. An application will generally function perfectly well by ignoring these events: the AWT toolkit will look after things such as calling layout managers on resize.

There are occasions when an application may want to track such events. For example, a visually intensive piece of graphics such as animation should cease when the display object becomes invisible, so it will want to track visibility changes. A ``smart'' text display may want to change the size of the font used according to the amount of space it has, so it will want to track size changes.

An application wanting to track such changes registers a listener that implements ComponentListener. This interface defines four methods that the listener must implement:

    public void componentHidden(ComponentEvent);
    public void componentMoved(ComponentEvent);
    public void componentResized(ComponentEvent);
    public void componentShown(ComponentEvent);
In objects of class ComponentEvent the id is used field to distinguish between four types: COMPONENT_HIDDEN, COMPONENT_MOVED, COMPONENT_RESIZED and COMPONENT_SHOWN. The AWT uses this value to select which of the four listener methods to call, so you are unlikely to need to look at this field.

The ComponentEvent class supplies a method

    public Component getComponent()
if you need to determine which component has called the listener.

Here is a program to track resize and movement events on the toplevel Frame:

import java.awt.*;
import java.awt.event.ComponentEvent;

public class TrackResize extends Frame {
 
   public static void main(String argv[]) {
	new TrackResize().show();
    }

    public TrackResize() {
	Label label = new Label();
	add(label);	
	pack();

	addComponentListener(new Tracker(label));
    }
}

class Tracker implements ComponentListener {

    private Label label;

    Tracker(Label l) {
	label = l;
    }
    public void componentHidden(ComponentEvent e) {
	// empty
    }

    public void componentMoved(ComponentEvent e) {
	showGeometry(e);
    }

    public void componentResized(ComponentEvent e) {
	showGeometry(e);
    }

    public void componentShown(ComponentEvent e) {
	// empty
    }

    private void showGeometry(ComponentEvent e) {
	Component c = e.getComponent();
	Dimension d = c.getSize();
	Point p = c.getLocation();

	label.setText("Position: (" + p.x +
		     "," + p.y + ") Size: (" +
		     d.width + "," + d.height + ")");
    }
}

The Tracker class inherits only from Object. Because it has to implement all of the ComponentListener interface it ends up with empty implementations of the componentHidden() and componentShown() methods. This may become mildly annoying if it had to be done frequently, so there is a ``convenience'' class ComponentAdaptor which defines all these methods as empty ones. Using this, you can inherit from ComponentAdaptor and then just override the methods you need. The single inheritance model of Java does of course then require that the listener cannot also inherit from other classes, so this may be of limited value.

Focus Events

Applications are unlikely to need to track focus events, as the AWT toolkit looks after most aspects of focus changes. If you need to, you can add a focus change listener by AddFocusListener(). The listener must then implement the methods
    public void focusGained(FocusEvent);
    public void focusLost(FocusEvent);
There are no extra methods for handling these events.

Item Events

Item events are generated for the following objects:
Table 8: Objects generating Item Events
GUI Object Action
Choice Click on item
Checkbox Select an item
Deselect an item
List Select an item
Deselect an item
Extend a selection
Reduce a selection

An application wanting to follow selection changes registers an object that implements ItemListener. When such a change occurs, it will have the method itemStateChanged() called with an ItemEvent as parameter.

Item event handling appears to be incomplete in Java 1.1 beta. The ItemEvent declares methods

    ItemSelectable getItemSelectable();
    Object getItem();
The interface ItemSelectable declares methods
    interface ItemSelectable {
        int[] getSelectedIndexes();
        String[] getSelectitems();
Presently, the classes that implement the ItemSelectable interface are List, Choice and Checkbox.

Now consider the information we would be after when an item in a list is selected: the index and the string showing. The index is given by the getItem() of the ItemEvent, but it has to be coerced to class Integer first. The actual string is not obtainable from the information given. The method getItemSelectable() returns the item that the selection was performed on - the list. From there you can find the set of all selected items (which may be more than one), but not the single list item that changed state. To get at that, you have to check and then coerce the ItemSelectable to class List and then use the List method getItem() to find the string selected.

// import java.awt.Label;
import java.awt.Color;
import java.awt.Component;
// import java.awt.Frame;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;

/**
 * An ItemListener that changes the foreground
 * color of a component passed in by the constructor
 *
 * @author Jan Newmarch
 */
public class SetColor2 implements ItemListener {
    final Color colors[] = {Color.red, Color.blue, Color.green};
    final String colorLabels[] = {"red", "blue", "green"};
    private Component comp;

    public SetColor2(Component c) {
	comp = c;
    }

    /**
     * Invoked by an item event somewhere
     * resets the foreground of a component passed
     * in to the constructor
     */
    public void itemStateChanged(ItemEvent e) {
	if (e.getStateChange == ItemEvent.SELECTED) {
	    System.out.println(e.getItem());
	    //String colorName = e.getActionCommand();

	    // search for Color matching color name
	    //for (n = 0; n < colorLabels.length; n++) {
		//if (colorLabels[n].equals(colorName)) {
		  //  comp.setForeground(colors[n]);
		    //return;
		//}
	    //}
	    //System.out.println("Unknown color: " + colorName);
	}
    }
}
import java.awt.*;

public class ListColor2 extends Frame {

    public static void main(String argv[]) {
	new ListColor2().show();
    }

    public ListColor2() {
	// the label that will be colored
	Label label = new Label("Hello World");
	// the list of colors
	List colors = new List(3);
	colors.add("red");
	colors.add("blue");
	colors.add("green");

	// set geometry
	add(colors, "West");
	add(label, "Center");
	pack();

	// add the listener
	SetColor2 sc = new SetColor2(label);
	colors.addItemListener(sc);
    }
}

Key Events

Key events may be generated for all components. They count as ``low level'' events for most objects, but of course for TextArea and TextField they really have semantic content. For other classes keyboard events are most likely to be use in implementing keyboard traversal mechanisms, such as the use of arrow keys to move around a grid of labels, or of the tab key to move between objects.

Key events also have an important property not shared with most other event types, and that is they can be changed by the application. For example, the application may change any text typed to lower case by mapping any upper case characters entered into lower case.

A KeyEvent defines a large number of constants for the special keys on the keyboard. These are known as action keys and are given in this table:
Table 9: Action Keys
HOME END PGUP PGDN
UP DOWN LEFT RIGHT
F1 - F12 PRINT_SCREEN SCROLL_LOCK CAPS_LOCK
NUM_LOCK PAUSE INSERT ENTER
BACK_SPACE TAB ESCAPE DELETE
These can be tested by code such as

    KeyEvent e;
    ...
    if (e.isActionKey()) {
	switch (e.getKeyCode()) {
	    case KeyEvent.HOME: ...
	    case KeyEvent.END:  ...
	    case KeyEvent.PGUP: ...
	    ...
	}
    }

There are related methods inherited from InputEvent, the super class of KeyEvent. These allow tests for the modifier keys:

    public boolean isShiftDown();
    public boolean isControlDown();
    public boolean isMetaDown();
The information from these can also be obtained from the method getModifiers(), and then comparing this to InputEvent.CTRL_MASK, etc.
import java.awt.*;
import java.awt.event.KeyListener;

public class ShowKey extends Frame {

    public static void main(String argv[]) {
	new ShowKey().show();
    }

    public ShowKey() {
	Label l = new Label("Hello");
	add(l);
	pack();

	KeyInfo ki = new KeyInfo();
	l.addKeyListener(ki);
    }
}

class KeyInfo implements KeyListener {

    public void keyPressed(KeyEvent e) {
	System.out.print("Down: ");
	printInfo(e);
    }

    public void keyReleased(KeyEvent e) {
	System.out.print("Up: ");
	printInfo(e);
    }

    public void keyTyped(KeyEvent e) {
	System.out.print("Typed: ");
	printInfo(e);
    }

    private void printInfo(KeyEvent e) {
	System.out.println(e.toString());
	System.out.println("char: " + e.getKeyChar() +
			   "keycode: " + e.getKeyCode());
    }
}

What is the difference between chars and keycodes, particularly with Unicode around?

Key events can have their value changed by the application. A simple use is to map all upper case keys down to lower case. We need to change the key value and also the modifiers value.

Mouse Events

Mouse Motion Events

Window Events

Changing and Generating Events

Discard keys for password entry.

Tab expansion replaces key.

A date entry TextField, where after each pair of numbers a '/' is added to the event queue.

Keyboard Traversal

Hot Keys