Events in JDK 1.1 : Java Glossary
home E words local find no local find frame, full screen Google search web for topic jump to footer translate with Babelfish by Roedy Green ©1996-2008 Canadian Mind Products
Go to : punctuation 0-9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z (all)
Events in JDK 1.1+
Introduction Actions Event vs. AWTEvent
Overview Consume Keystroke Events
The Cast Anatomy Keystroke Names
Conception Cremation Synthetic Events
Event Loop TABLE JDK 1.0
Creation Censoring JDK 1.3+
Enqueuing Activating Repaint
Dispatching textValueChanged Credits
Classification Missing Events Summary
Notifying Mouse Events Links
Listeners Mouse Buttons

Introduction

In JDK 1.1, Events are handled quite differently from JDK 1.0.2. This essay will follow an single Event from creation to cremation to give you an idea of how it all fits together. For details, and practical coding concerns, I suggest you read some other essays on Events such as Richard Baldwin’s instructional essays or Jan Newmarch’s essay on JDK 1.1+ events. I have written a similar essay for the older JDK 1.0.2 Events.

I’m a guy who can’t use a tool until I have some model of how it works under the hood. If you are that way, you will like this essay. If you are the kind of programmer who simply wants to use the tool without any interest of how it works inside, all you need pay attention to in this essay is how EventListeners work.

Overview

Events are: Events are hard to understand because there are three different mechanism meshing.
  1. A callback delegate mechanisms so that Sun-written Components can call code you write when something interesting happens via the various listener interfaces. The listener mechanism is more complex than your usual callback. The callee, remembers multiple callers, then calls them back later, asynchronously when something interesting happens.
  2. A queuing mechanism to procrastinate work. Basically it is a to-do list. High priority work gets done first. If the system gets behind, it can skip some of the validates or repaints since the later ones will cover the earlier ones. The queue mechanism also co-ordinates many Threads all making changes to the screen at once. They put their requests into a queue and a single Thread does all the work without any worries of other Threads interfering.
  3. It is also an Event delivery mechanism so that an Event (notification of something interesting happening) can be easily forwarded to other possibly interested parties.
Instead of Events percolating up to parents as they did in JDK 1.0.2, any object or component can register itself as a listener, interested in hearing about a type of Events originating in some other component. When the Event arises, the source component processes the Event by dispatching it to each of the registered listeners. Dispatching is synchronous, i.e. the listener handler routines are called directly while the calling dispatcher waits for the handler to complete. According to the specification, the listeners may be informed in any order, but the usual implementation is a queue, with listeners informed in the same order they were added. If you want to be absolutely sure of a fixed order of handling listeners, make your own chain and pass the Event between them. listeners pretty much only hear Events they are interested in. They are not responsible for passing the Event on to anyone else.

The new Event model gives you three places to hook in your code to process Events.

  1. via listeners. This is by far the most common way and the easiest to set up. The listener can be any object, e.g. the enclosing frame, the component itself, a non-GUI code object, a "mom" object to mother a set of components. A given listener can service several sources, and a given source can notify several target listeners. listener methods have names like actionPerformed, windowClosed, mouseMoved. Listeners are often implemented with Adapter classes so you don’t have to write dummy methods for Events you are not interested in. Adapter classes have names like: java.awt.event.FocusAdapter, KeyAdapter and WindowAdapter. Note, there is no such thing as ActionAdapter since it has only one method. Often you use inner classes or anonymous classes to handle fielding Events by extending an adapter class. Be very careful in extending adapter classes to get your method names and signatures exactly right. Otherwise you won’t override the corresponding dummy method, and your code won’t ever be executed, leaving you wondering where all the Events went.
  2. via processEvent which receives all raw Events for the component. It does not see Events coming in via listeners. If you override it, be sure to call super.processEvent to ensure all the finer Event handlers, like processKeyEvent, ProcessActionEvent etc. also get called and the listeners alerted. If you attempt to restrict the Events coming to processEvent with enableEvents(mask), if there are listeners registered for Events not in the mask, those Event classes will arrive anyway.
  3. via processXXXX(SomeEventClass e), e.g. processActionEvent, processItemEvent. Every raw Event for the component of that class comes through here. It does not see Events coming in via listeners. Be sure to call super.processXXXX to ensure the listeners are alerted.
A component might quite reasonably register itself as a listener for Events arising in itself or for Events arising from the associated native GUI. There is another deprecated technique to process Events arising in itself. A component could override its processEvent routine, do some action, then call super.processEvent (which would inform all the listeners), then do some other action.

The Cast Of Players

Methods for registering a target as a listener of Events arising in some source include: source.addActionListener(target), addAdjustmentListener, addComponentListener, addContainerListener, addFocusListener, addItemListener, addKeyListener, addMouseListener, addMouseMotionListener, addPropertyChangeListener, addTextListener, addVetoableChangeListener, addWindowListener… Normally you would invoke these methods but not override them.

The AWT informs the list of registered listeners that an Event has occurred by calling the generic source.processEvent which in turn calls the more specific Event handler: source.processActionEvent, processAdjustmentEvent, processComponentEvent, processContainerEvent, processItemEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, firePropertyChange, processTextEvent, fireVetoableChange, processWindowEvent… These routines would in turn use the AWTEventMulticaster to inform all the listeners and invoke their actionPerformed, keyPressed, windowOpened etc. methods in turn. These processXXX routines typically work by calling the relevant dispatching routines on the listener targets. It is unlikely you will ever deal with these methods directly.

Your listener object must implement one or more interfaces such as: ActionListener, ComponentListener, ContainerListener, FocusListener, KeyListener, ItemListener, MouseListener, MouseMotionListener, TextListener, WindowListener…

The easiest way to implement those interfaces is to extend one of the related adapter classes. The adapter classes provide dummy methods to deal with the subcategories of Events that are of no interest to you. ComponentAdapter, ContainerAdapter, FocusAdapter, KeyListener, ItemAdapter, MouseAdapter, MouseMotionAdapter, TextAdapter, WindowAdapter…

The Event is dispatched to each target Listener by invoking its listening method. These have names like: target.actionPerformed, adjustmentValueChanged, componentHidden, componentMoved, componentResized, componentShown, componentAdded, componentRemoved, focusGained, focusLost, itemStateChanged, keyPressed, keyReleased, keyTyped, mouseClicked, mouseEntered, mouseExited, mousePressed, mouseReleased, textValueChanged, windowActivated, windowClosed, windowClosing, windowDeactivated, windowDecionified, WindowIconified, windowOpened… You need to write custom versions of these routines.

If there is a listener for an Event type registered, then Events from the GUI for that Event type will be delivered to that component’s processEvent. The component can control which additional types are delivered to processEvent by calling enableEvents with a mask. This way events that no one is interested in are not even delivered to processEvent. It is unlikely you will be directly involved with enableEvents.

A key point to understand is that a component has two kinds of acceptor routines for Events.

  1. The generic processEvent routine primarily accepts Events indirectly coming from the native GUI. Application programmers do not normally use these methods.
  2. The listener methods, e.g. actionPerformed, accept Events from other components. This is the main tool for application programmers to deal with Events. Component writers can also use the EventListener interface by registering a custom component as a listener to Events arising in itself.

The Life Cycle Of An Event

Where do Events Come From Daddy?

You synthesize an AWTEvent and post to the SystemEventQueue for later delivery.
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent( Event e );
In this Alice in Wonderland world, you set the source field of the Event to the component or peer where you want the Event delivered. Later, when the source delivers the Event to the various listeners, the term source for this field will make more sense. A potentially separate thread will service the queue asynchronously. When the Event percolates to the head of the queue, the dispatcher will call event.getSource().processEvent(event);

Most Events arise in the native GUI. They can enter the Java system in one of two ways:

  1. Notification of interesting happenings in the GUI arrive as a single stream of messages mentioning native GUI components. This is the traditional native GUI Event loop handled by hidden code, that calls getMessage() in a loop. The AWT uses a hash table to convert references to native GUI components into the corresponding Java components and peers, and composes corresponding Java Events and enqueues them in the SystemEventQueue.
  2. Java peer components generate Events based on information they glean from the native GUI. These too are enqueued in the SystemEventQueue.
Lightweight components generate Events and post them directly to themselves, without going through the SystemEventQueue.

Where is the Event Loop?

People who cut their teeth in the Windows or Mac native low level GUI API are used to writing application-specific code to handle dispatching using an Event processing loop. The AWT handles this all automatically and invisibly in EventDispatchThread.run. It reads the stream of native GUI Event messages, and translates them, creating Java Events, which it puts into the SystemEventQueue. The thread that processes Events, when it finishing processing one Event, goes and picks up another Event off the head of the Event queue to dispatch. This is the very thread that executes most of your application code.

The loop that processes Events does not even start until your main program has finished executing!! This Event loop code is not visible to the application programmer.

You might naively imagine there is some sort of mail delivery service that delivers Events to their destinations. It is much simpler than that. The Event object contains a reference to the target object. To deliver/dispatch the Event, all the system has to do is call a method on that reference. It is a little more complicated than that since an Event handler may call a chain of Event handlers. The target object is confusingly called the source. It makes sense if you consider that Events usually come back to the same object that generated them. From the point of view of listeners, the Events appear to come from these source objects.

You can think of Events as a way of enqueing work to be done later, usually by other objects.

Creation

Consider what happens behind the scenes when the user clicks an OK button on the screen. The underlying native GUI notices the mouse click.
It could then work one of two ways:
  1. The native GUI indirectly notifies the Java Button peer object which creates a new Event using the ActionEvent constructor.
  2. The GUI creates a native format message that a button has been clicked. Hidden code in the AWT reads this stream of messages and translates this one into a new Event using the ActionEvent constructor. It has a Hashtable to convert references to native peer components to the corresponding Java components.
  3. event source
    A Java component closely associated with this event, namely myButton. At first this field acts as the destination for the Event. Later it informs listeners where the Event came from.
    event id
    the type of event, in this case ActionEvent.ACTION_PERFORMED.
    event command
    the command string for this action event. In this case it would be the string "OK".
    event modifiers
    the modifiers held down during this click, e.g. CTRL_MASK if the Ctrl key is held down

Enqueuing

The newly created Event is then enqueued on the system Event queue using:
EventQueue q = Toolkit.getDefaultToolkit().getSystemEventQueue();
Now it can enqueue the Event for delivery to the source ( myButton) with the system’s postEvent method. We don’t use any methods of myButton just yet.
q.postEvent( e );
The Event hibernates in the queue waiting its turn to be dispatched. postEvent will return immediately. It won’t wait until the new Event has been delivered.

Dispatching

There is a single system thread that grabs the next item off the queue and dispatches it. You can see the code for it in EventDispatchThread.run When all the processing for that Event is complete, it gets the next Event. No other Event processing, not even a mouse move, can happen until the previous Event has been processed. I repeat, only one Event is processed at a time.

Having said that, this single-thread behaviour is not part of the specification. There are some JVMs where you have several threads processing Events simultaneously.

It looks at the source field in the Event object, and delivers the Event to that source object.

First it checks the java.awt.Component.eventMask to be sure the myButton component is willing to accept that flavour of Event.

The button could conceivably have used java.awt.Component.disableEvents to filter out Events such as ours. disableEvents takes bit masks for groups of Events such as java.awt.AWTEvent.MOUSE_MOTION_EVENT_MASK. You cannot feed it individual Events such as java.awt.event.MouseEvent.MOUSE_ENTERED, because these constants are not in bit mask form. One my main bitches about Java is this bit map / enumeration ambiguity.

It also checks if there are listeners for our type of Event. If there are, even if our Event type is blocked, our Event will still be delivered.

It delivers the Event to the button component by calling myButton’s generic processEvent Event handler:

myButton.processEvent( e );
or more precisely:
e.getSource().processEvent( e );
This dispatching mechanism is efficient because it does not require any sort of table lookup or nested switch statements.

Classification

processEvent could in theory do some special processing on the Event, but usually all it does is classify the Event and call a more specialised Event handler such as: processActionEvent. (If you override processEvent, make sure you call super.processEvent to ensure the standard Event processing also occurs.) Had we been processing a mouse Event, we would have called processMouseEvent instead.

Notifying Listeners

A long time ago, before this Event was born, parties interested in this type of Event registered their interest my using myButton. addActionListener(myListener). It is important to remember that addXXXXListener methods are implemented by the sources, not the listeners. In theory, the addXXXXListener methods could be invoked by the source or the listener, but usually they are invoked by a third party, usually an enclosing frame.

Raw Events arrive via processEvent. They are classified and redirected to more specialised Event processors like processActionEvent.

processActionEvent can further classify the incoming Events and can do whatever special processing it wants. Then it notifies any listeners, one after the other. (If you override processActionEvent, make sure you call super.processActionEvent to ensure the listeners are notified.)

Each listener effectively gets a fresh cloned copy of the original Event. Unfortunately, this wastes cpu cycles and creates a ton of run time garbage. The intent is to make Events effectively read-only and to render harmless any malicious component that stored a reference to an Event. Once an Event enters Component.processKeyEvent, it isn’t replicated anymore so presumably some of its fields could be modified and used for communication. Ideally Event objects would be read-only and recyclable.

There is no guarantee that the listeners will be notified in any particular order, however they will be notified one at a time, never in parallel.

To notify each registered listener, the speaker’s processActionEvent calls each listener’s actionPerformed(e) method by chasing the AWTEventMultiCaster listener chain.

AWTEventMulticaster contains generic code that most components use for implementing addXXXListener and the notification of listeners. Component has various add/remove listener methods that use AWTEventMulticaster that all Components inherit.

If we had been processing a mouse motion, we would have called the listener’s mouseMoved method instead. processActionEvent methods are designed to be called by processEvent; methods like actionPerformed and mouseMoved are part of listener interfaces. Most application coding uses only listeners. Only if you were inventing a new sort of component would you get involved with processEvent and processActionEvent.

What Are Listeners?

A Listener is any object that:
  1. implements one of the EventListener interfaces such as ActionListener. E.g. an ActionListener must implement an actionPerformed method to be called when an Action Event occurs.
  2. Has hooked itself (or been hooked by a third party) onto one or more Event-generating components with a method such as addActionListener.
Listeners are written mostly by application programmers to field notifications of interesting things that happen to Sun-written widgets such as JButtons.

A listener might be a component, an ordinary object, a special Mom object to mother a set of components or an anonymous object created from an anonymous class to simply provide a hook to some other routine.

A listener might be created by extending one of the adapter shortcut classes. The adapter classes give you some dummy classes to start with in defining a listener where you only want to handle a few types of Event.

A component may even register itself as a listener for Events originating it itself. This is the preferred method for application programmers since there is less possibility of mucking up standard Event processing.

A listener can field Events from many different sources. Similarly a source may notify many different listeners. Alternatively you could have a separate listener object for every source, or anything in between.

Components like JButtons implement interfaces like ItemSelectable. The provide methods like addItemListener so that classes that implement the ItemListener interface can arrange to be notified of interesting events in the button, such as it being pressed by first hooking themselves up through JButton.addItemListener.

The JButton uses EventListenList to maintain the list of interested listeners. When something interesting happen its calls fireActionPerformed which calls each of the actionPerformed methods of the register listeners. Even though an event gets passed to the actionPerformed method, the listener mechanism does not necessarily mean the event spent any time in a queue. It could be created and passed immediately to the listeners when the interesting event happened.

You could even use the listener mechanism in your own code, for both the notifier and listener end, for situations where it is hard to keep track of who should notify whom when some interesting thing happens. You don’t need to modify the callee’s code to add more interested parties. You don’t need an event queue.

You can also set up a listener to monitor all the events. You might use this to monitor keyboard or mouse activity for a timeout to shutdown after a period of inactivity.

Listener Actions

What does the listener do when it’s actionPerformed (or other mouseMoved etc…) method is called? It may classify the incoming Event based on source, id or class (via instanceof). Then it would perform some action, do a calculation, change the look of the screen, delete a file… If it wants, it can use the consume() method to mark the Event consumed to discourage further processing on it.

It had better be quick! The entire system is at a standstill, unable to process any more Events until your listener completes its action. If the action is going to take more than a few milliseconds you should either:

In a similar vein, if it is very important that some action not start until after the physical paint is finished, the simplest way to arrange that is to have paint kick it off, perhaps by examining some flag to see if kickoff is necessary.

How Does consume() Work?

I have not found a precise definition of what is supposed to happen to a consumed Event. By experiment, I discovered it seems to stop further processing by the base classes of the current component. It does not seem to stop notification of others listeners. I found for example that in TextField, consuming a keystroke Event would prevent it being displayed. However, this does not work with the KL group JCTextField or the Swing JTextField. There you must override processKeyEvent.

After all the listeners have been called, the Event is checked to see if it has been consumed. If so, then it is not passed onto the next stage. For e.g. KeyEvents for a TextArea, this means that it is not passed back to the peer, and so does not reach the underlying window/widget, and so does not appear.

consume() in KeyListeners is effectively broken in Swing 0.7 since it is ignored. It looks like the Event is drawn in JTextArea before being given to the listeners.

For TextFields, you can change the value of the keystroke in the Event in a KeyListener before passing it on, e.g. convert it to lower or upper case. However under Motif, converting to lower case is broken, and the entire technique is broken for Swing. You would have to trap processKeyEvent instead. In a TextField in the AWT, you get the Event before the character has been painted on the screen. Therefore if you do a getText or setText in your Event handler, very likely will thoroughly confuse the AWT. The AWT was not designed to do anything useful, just to look good on paper. To save your sanity, it is perhaps best to look on the AWT as an mystery/adventure game. Your task is to figure out by experiment what the methods do. Their names give you the barest of clues. You then McGuyver-like must cobble the odd bits together to create something practical.

How Do You Compose a Listener?

Java 1.1 added inner classes and anonymous classes to make it easier to hook up listener code. Here is code that could appear in the middle of a frame initialisation method that:
  1. defines a new anonymous class that extends the WindowAdapter listener.
  2. defines a method in that class to deal with window closing Events.
  3. allocates an object of that class.
  4. hooks that object up as a listener to the current frame component.
  5. throws away the reference to the class. (The object won’t die since it is on the list of listeners.)

Cremation

The various listeners eventually complete their work and return to actionPerformed. The return stack unwinds: actionPerformed returns. processActionEvent returns. processEvent returns. We are now back at system the code that dispatches Events from the queue. Our Event is forgotten and the next Event takes the stage. With no more references to our old Event, garbage collection soon recycles the RAM that the Event occupied.

Table of Event Classes and Methods

Now we need to generalise from those specific examples.

Instead of creating an ActionEvent with id ActionEvent.ACTION_PERFORMED, that is dispatched to processEvent, then passed on to processActionEvent, then passed on to an ActionListener (that registered its interest via addActionListener) via its actionPerformed method, there are many other possibilities you can generate from the following table:

When Event Class id Specific
Event
Handler
Listener
Interface
Listener
Notification
Method
Listener
registration
Adapter shortcut Typical Components
Button clicked, MenuItem clicked, but not Choice selected. ActionEvent ACTION_PERFORMED processActionEvent ActionListener actionPerformed addActionListener   Button, JButton, MenuItem, JMenuItem
Slider moved AdjustmentEvent ADJUSTMENT_VALUE_CHANGED processAdjustmentEvent AdjustmentListener
ScrollPane
adjustmentValueChanged addAdjustmentListener   JSlider
Component hidden, moved, resized, revealed. ComponentEvent COMPONENT_HIDDEN
COMPONENT_MOVED
COMPONENT_RESIZED
COMPONENT_SHOWN
processComponentEvent ComponentListener componentHidden
componentMoved
componentResized
componentShown
addComponentListener ComponentAdapter Component
something added or removed to this container. ContainerEvent COMPONENT_ADDED
COMPONENT_REMOVED
processContainerEvent ContainerListener componentAdded
componentRemoved
addContainerListener ContainerAdapter Container, Panel, Jpanel, Frame, JFrame
Focus changed, either by mouse or tab FocusEvent FOCUS_GAINED
FOCUS_LOST
processFocusEvent FocusListener focusGained
focusLost
addFocusListener FocusAdapter Component
Ancestor added or removed HierarchyEvent HIERARCHY_CHANGED processHierarchyEvent HierarchyListener hierarchyChanged addHierarchyListener Component
Ancestor moved or resized HierarchyBoundsListener ANCESTOR_MOVED ANCESTOR_RESIZED processsHierarchyBoundsEvent HierarchyBoundsListener ancestorMoved
ancestorResized
addHierarchyBoundsListener Component
user keyed something into a text box InputMethodEvent INPUT_METHOD_TEXT_CHANGED
CARET_POSITION_CHANGED
processInputMethodEvent InputMethodListener inputMethodTextChanged
caretPositionChanged
addInputMethodListener   Component
user selected a different Choice ItemEvent DESELECTED
ITEM_STATE_CHANGED
SELECTED
processItemEvent ItemListener itemStateChanged addItemListener   Choice, JComboBox
keystroke KeyEvent KEY_PRESSED (e.g. shift, F1)
KEY_RELEASED
KEY_TYPED (e.g. a A)
processKeyEvent KeyListener keyPressed
keyReleased
keyTyped
addKeyListener KeyAdapter Panel, JPanel, Frame, JFrame
not Button, JButton, TextArea, JTextArea, Choice, ComboBox, Checkbox, JCheckbox
Mouse clicked, entered or exited the region. See also ActionEvent and Item event. MouseEvent MOUSE_CLICKED
MOUSE_ENTERED
MOUSE_EXITED
MOUSE_PRESSED
MOUSE_RELEASED
processMouseEvent MouseListener mouseClicked
mouseEntered
mouseExited
mousePressed
mouseReleased
addMouseListener MouseAdapter Component, Canvas, Panel, JPanel,
not Button, JButton, TextArea, JTextArea, Choice, ComboBox, Checkbox, JCheckbox
Mouse moved. You normally don’t want to track these since there are so many of them. MouseMotionEvent MOUSE_DRAGGED
MOUSE_MOVED
processMouseMotionEvent MouseMotionListener mouseDragged
mouseMoved
addMouseMotionListener MouseMotionAdapter Component, Canvas, Panel, JPanel,
not Button, JButton, TextArea, JTextArea, Choice, ComboBox, Checkbox, JCheckbox
Mousewheel moved. MouseWheelEvent   processMouseWheelEvent MouseWheelListener mouseWheelMoved addMouseWheelListener Component
Canvas
JPanel
repaint PaintEvent PAINT
UPDATE
paint
update
        Component
value in a TextField changed. TextEvent TEXT_VALUE_CHANGED processTextEvent TextListener textValueChanged addTextListener   TextField, TextArea, JTextField, JTextArea
Window state change WindowEvent WINDOW_ACTIVATED
WINDOW_CLOSED
WINDOW_CLOSING
WINDOW_DEACTIVATED
WINDOW_DEICONIFIED
WINDOW_ICONIFIED
WINDOW_OPENED
processWindowEvent WindowListener windowActivated
windowClosed
windowClosing
windowDeactivated
windowDecionified
WindowIconified
windowOpened
addWindowListener WindowAdapter Frame, JFrame, Window, JWindow, Dialog, JDialog
For a complete list of the various Listener interfaces, and methods see the JDK API/Package-java.awt.event.html if you want to study the whole java.awt.event package.

Censoring or Remapping Keystrokes

Let us say you wanted to write your own version of TextField-like component that disallowed certain keystrokes, or that processed certain keystrokes specially. You may have tried the easy Listener/consume() method and discovered it did not work for your base component. Here is bigger hammer to use:
If you want the underlying base class not to see the Event, you consume it in one of your custom filter routines such as unicodeKeyPressed(e), and that suppresses the call to super.processKeyEvent. Something to baffle you. Hitting the Enter key under NT generates two keystrokes a \r and a \n. On other platforms you get just a \n. Best just to look for VK_ENTER.

In Swing you can use the Keymap and KeyStroke classes to control the actions of various keystrokes.

Activating

To activate your Listener, you need to create a callback delegate Listener object, and pass it to the Component. Then when something interesting happens, it can call one of the methods you wrote (to its interface specifications), perhaps indirectly via the Event queue.

Styles Of Activating

There are several styles for activating:
  1. compact

    You do it all in one very complicated line, where you define an anonymous class, create an instance of it and feed it to the addListener method. The puts everything in one place. The code is an unreadable forest of parentheses braces and semicolons. They limit you to one component per listener. They generate one extra inner class per use. They don’t have to deal with the problem of figuring out which component the incoming event to the listener is relevant too. There is only one possibility. Java beautifiers tend to over-indent this style. Inner classes get total and easy access to all the mother class’s fields. The examples that follow are all of this style.
  2. anonymous class reference

    You create a reference to a anonymous inner class object then in a separate step, feed that to the addListener method. I prefer this to (1) because it is easier to proofread and SlickEdit beautifier renders it without excessive indentation. You have the option of reusing a Listener on several components. You can also collect all your listener logic in one place separate from the GUI logic which makes it easier to maintain. This is the style I most commonly use personally.
  3. named inner class reference

    Like (2), but you name the inner classes. Perhaps a little easier for notices to understand.
  4. named free standing classes

    like (3) but with ordinary classes that implement the Listener interfaces. They don’t have easy access to the parent class variable. You can use designs where the mother class itself implements the Listener interface, or where the Listener classes have additional functionality. The Listener classes can have parameters in their constructors, which anonymous inner classes cannot. This is the most flexible approach, but also requires the most typing.
  5. Stomp Style

    These are mechanically generated. One master hookListeners method calls a separate method to hook up each component. Those methods in turn build an anonymous listener and link it to the widget. On activation they call one line of code, which is yet another method that actually does the work. It is verbose, but easy to proofread because the important stuff is separated from the bubblegum. Here is what you type:
I would be happy to share my Stomp cookie cutter classes for you.

Activating a Button

Hooking up some code to be executed when a button is hit is very similar to the earlier WindowClosing example. There is no such thing as the ActionAdapter class, so we use the name of the interface instead.

Activating a FocusListener

Activating a KeyListener

Activating a Choice or JCheckbox ItemListener

JMenuItems

Just a few simple menus will explode into gobs of code if you provide an anonymous ActionListener for each JMenuItem. Instead, use a common ActionListener for all JMenuItems or all JMenuItems in a JMenu. Give each JMenuItem a one-letter setActionCommand string. In your ActionListener, extract the command letter with getActionCommand().charAt(0) and use it to index a switch to select the piece of code that needs to execute. Remember to add your ActionListener to every individual JMenuItem. Best look into Actions for hooking up your JButtons and JMenuItems if you have more than a handful.

TextListener.textValueChanged

This method receives an event any time the text value of the component changes including when you change it programmatically with setText! This can cause your program to go into heart fibrillation, if your event handler does any setTexts that in turn will trigger further Events in a Disney-style ping-pong-balls-on-the-mousetraps fission-style chain reaction. To add to the confusion, the some versions of the JDK don’t do this.

Missing Events

The newsgroups are full of plaintive messages from newbies claiming the AWT is broken because their listeners are not receiving any Events. Here are some things to check:

Mouse Events

There are three different listeners for the mouse, MouseListener, MouseMotionListener and MouseWheelListener.

If you click the mouse, you will get three events which will show up at mousePressed, then mouseReleased then mouseClicked.

If you move the mouse onto your component you will first get an event at mouseEntered. If you move if off the component, you will get an event at mouseExited.

Every time you move the mouse even a tad, you will get an event at mouseMoved.

If you press a mouse button and drag you will get an event at mousePressed followed by multiple events at mouseDragged reporting the current drag location. When you let go of the button, you get an event at mouseReleased. You won’t get an event at mouseClicked

If you twirl the wheelmouse on a Component in a ScrollPane, you won’t see events at the Component’s mouseWheelmoved. Instead you will see events at mouseMoved, as if there were no ScrollPane and user had moved the mouse instead. Events are mouseMoved are about relative motion over the virtual panned Component in the ScrollPane.

Detecting Shift, Alt and Ctrl, Left and Right Mouse Buttons

When the user hits Shift, Alt or Ctrl (or a combination) in conjunction with some ordinary key, you can determine that by looking at the KeyEvent.getModifiers, masking with ORed combinations of inputEvent.SHIFT_MASK, ALT_MASK, CTRL_MASK and META_MASK, in your keyTyped listener.

You can detect the separate pressing of Shift, Alt or Ctrl at the keyPressed() listener, and the releasing at the keyReleased listener, by testing KeyEvent.getKeyCode() for a match with KeyEvent.VK_SHIFT, VK_CONTROL, VK_ALT and KeyEvent.VK_META.

With the advent of JDK 1.3, you can detect and set the state of the various CapsLock-like states with: public boolean getLockingKeyState(int keyCode) and public void setLockingKeyState(int keyCode, boolean on). Valid key codes are: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, VK_KANA_LOCK.

Dealing with mouse clicks is similar. In your mouseClicked listener, MouseEvent.getModifiers() returns the state of all the modifier keys and mouse buttons when the event was fired. You can use this method to determine which mouse button was pressed (or newly released) when a mouse Event was fired. You mask the result with an ORed combination of InputEvent.ALT_MASK, BUTTON1_MASK, BUTTON2__MASK, BUTTON3_MASK, CTRL_MASK, META_MASK, and SHIFT_MASK. For example, the following expression is true if the right button was pressed:

The various combinations of ID, keyCode() and keyChar() in the KeyEvent are quite complicated.

getID() tells you the type of event, basically which listener was used. KeyCode() gets you a raw Keyboard code e.g. "A". keyChar() gets you the cooked character e.g. "a". See KeyListener in the Java glossary for more discussion.

I suggest downloading my little KeyPlay application. You can play with it, clicking the mouse and hitting keystrokes. A description of the Events generated is dumped to the console. With it, you can quickly learn about the ordering of Events, and the use of the fields. You will discover most JVMs work the same way, with the exception of Microsoft’s which is out in left field. Check out Sun’s java.awt. Robot class for generating simulated keystrokes and mouse moves.

Keystroke Events

Whenever you hit a key on the keyboard, three events will show up at your KeyListener, first an event at keyPressed, then at keyTyped, then at keyReleased. If you hold a key down and it repeats, you will see that triple repeated over and over. If you hit the ctrl key and hold it down you will see repeated events at keyPressed and finally one at keyReleased when you let go. There is no event at keyTyped. When you hit Ctrl+C you see keyCode 03, ^C, ETX not the letter C. Java combines the keys for you. It is not your problem to track the ctrl or shift state and modify the meanings of other keystrokes.

Keystroke Names

You should write your code using these KeyChar and KeyCode names from java.awt.event.KeyEvent rather than hard-coding the numeric literals.
Numeric Ordering
name decimal hex
VK_UNDEFINED 0 0x0
CHAR_UNDEFINED 0 0x0
VK_CANCEL 3 0x3
VK_BACK_SPACE (\b) 8 0x8
VK_TAB (\t) 9 0x9
VK_ENTER (\n) 10 0xa
VK_CLEAR 12 0xc
VK_SHIFT 16 0x10
VK_CONTROL 17 0x11
VK_ALT 18 0x12
VK_PAUSE 19 0x13
VK_CAPS_LOCK 20 0x14
VK_KANA 21 0x15
VK_FINAL 24 0x18
VK_KANJI 25 0x19
VK_ESCAPE 27 0x1b
VK_CONVERT 28 0x1c
VK_NONCONVERT 29 0x1d
VK_ACCEPT 30 0x1e
VK_MODECHANGE 31 0x1f
VK_SPACE 32 0x20
VK_PAGE_UP 33 0x21
VK_PAGE_DOWN 34 0x22
VK_END 35 0x23
VK_HOME 36 0x24
VK_LEFT 37 0x25
VK_UP 38 0x26
VK_RIGHT 39 0x27
VK_DOWN 40 0x28
VK_COMMA 44 0x2c
VK_PERIOD 46 0x2e
VK_SLASH 47 0x2f
VK_0 48 0x30
VK_1 49 0x31
VK_2 50 0x32
VK_3 51 0x33
VK_4 52 0x34
VK_5 53 0x35
VK_6 54 0x36
VK_7 55 0x37
VK_8 56 0x38
VK_9 57 0x39
VK_SEMICOLON 59 0x3b
VK_EQUALS 61 0x3d
VK_A 65 0x41
VK_B 66 0x42
VK_C 67 0x43
VK_D 68 0x44
VK_E 69 0x45
VK_F 70 0x46
VK_G 71 0x47
VK_H 72 0x48
VK_I 73 0x49
VK_J 74 0x4a
VK_K 75 0x4b
VK_L 76 0x4c
VK_M 77 0x4d
VK_N 78 0x4e
VK_O 79 0x4f
VK_P 80 0x50
VK_Q 81 0x51
VK_R 82 0x52
VK_S 83 0x53
VK_T 84 0x54
VK_U 85 0x55
VK_V 86 0x56
VK_W 87 0x57
VK_X 88 0x58
VK_Y 89 0x59
VK_Z 90 0x5a
VK_OPEN_BRACKET 91 0x5b
VK_BACK_SLASH 92 0x5c
VK_CLOSE_BRACKET 93 0x5d
VK_NUMPAD0 96 0x60
VK_NUMPAD1 97 0x61
VK_NUMPAD2 98 0x62
VK_NUMPAD3 99 0x63
VK_NUMPAD4 100 0x64
VK_NUMPAD5 101 0x65
VK_NUMPAD6 102 0x66
VK_NUMPAD7 103 0x67
VK_NUMPAD8 104 0x68
VK_NUMPAD9 105 0x69
VK_MULTIPLY 106 0x6a
VK_ADD 107 0x6b
VK_SEPARATER (sic) 108 0x6c
VK_SUBTRACT 109 0x6d
VK_DECIMAL 110 0x6e
VK_DIVIDE 111 0x6f
VK_F1 112 0x70
VK_F2 113 0x71
VK_F3 114 0x72
VK_F4 115 0x73
VK_F5 116 0x74
VK_F6 117 0x75
VK_F7 118 0x76
VK_F8 119 0x77
VK_F9 120 0x78
VK_F10 121 0x79
VK_F11 122 0x7a
VK_F12 123 0x7b
VK_DELETE (ASCII del) 127 0x7f
VK_NUM_LOCK 144 0x90
VK_SCROLL_LOCK 145 0x91
VK_PRINTSCREEN 154 0x9a
VK_INSERT 155 0x9b
VK_HELP 156 0x9c
VK_META 157 0x9d
VK_BACK_QUOTE 192 0xc0
VK_QUOTE 222 0xde
Alpha Ordering
name decimal hex
CHAR_UNDEFINED 0 0x0
VK_0 48 0x30
VK_1 49 0x31
VK_2 50 0x32
VK_3 51 0x33
VK_4 52 0x34
VK_5 53 0x35
VK_6 54 0x36
VK_7 55 0x37
VK_8 56 0x38
VK_9 57 0x39
VK_A 65 0x41
VK_ACCEPT 30 0x1e
VK_ADD 107 0x6b
VK_ALT 18 0x12
VK_B 66 0x42
VK_BACK_QUOTE 192 0xc0
VK_BACK_SLASH 92 0x5c
VK_BACK_SPACE (\b) 8 0x8
VK_C 67 0x43
VK_CANCEL 3 0x3
VK_CAPS_LOCK 20 0x14
VK_CLEAR 12 0xc
VK_CLOSE_BRACKET 93 0x5d
VK_COMMA 44 0x2c
VK_CONTROL 17 0x11
VK_CONVERT 28 0x1c
VK_D 68 0x44
VK_DECIMAL 110 0x6e
VK_DELETE (ASCII del) 127 0x7f
VK_DIVIDE 111 0x6f
VK_DOWN 40 0x28
VK_E 69 0x45
VK_END 35 0x23
VK_ENTER (\n) 10 0xa
VK_EQUALS 61 0x3d
VK_ESCAPE 27 0x1b
VK_F 70 0x46
VK_F1 112 0x70
VK_F10 121 0x79
VK_F11 122 0x7a
VK_F12 123 0x7b
VK_F2 113 0x71
VK_F3 114 0x72
VK_F4 115 0x73
VK_F5 116 0x74
VK_F6 117 0x75
VK_F7 118 0x76
VK_F8 119 0x77
VK_F9 120 0x78
VK_FINAL 24 0x18
VK_G 71 0x47
VK_H 72 0x48
VK_HELP 156 0x9c
VK_HOME 36 0x24
VK_I 73 0x49
VK_INSERT 155 0x9b
VK_J 74 0x4a
VK_K 75 0x4b
VK_KANA 21 0x15
VK_KANJI 25 0x19
VK_L 76 0x4c
VK_LEFT 37 0x25
VK_M 77 0x4d
VK_META 157 0x9d
VK_MODECHANGE 31 0x1f
VK_MULTIPLY 106 0x6a
VK_N 78 0x4e
VK_NONCONVERT 29 0x1d
VK_NUM_LOCK 144 0x90
VK_NUMPAD0 96 0x60
VK_NUMPAD1 97 0x61
VK_NUMPAD2 98 0x62
VK_NUMPAD3 99 0x63
VK_NUMPAD4 100 0x64
VK_NUMPAD5 101 0x65
VK_NUMPAD6 102 0x66
VK_NUMPAD7 103 0x67
VK_NUMPAD8 104 0x68
VK_NUMPAD9 105 0x69
VK_O 79 0x4f
VK_OPEN_BRACKET 91 0x5b
VK_P 80 0x50
VK_PAGE_DOWN 34 0x22
VK_PAGE_UP 33 0x21
VK_PAUSE 19 0x13
VK_PERIOD 46 0x2e
VK_PRINTSCREEN 154 0x9a
VK_Q 81 0x51
VK_QUOTE 222 0xde
VK_R 82 0x52
VK_RIGHT 39 0x27
VK_S 83 0x53
VK_SCROLL_LOCK 145 0x91
VK_SEMICOLON 59 0x3b
VK_SEPARATER (sic) 108 0x6c
VK_SHIFT 16 0x10
VK_SLASH 47 0x2f
VK_SPACE 32 0x20
VK_SUBTRACT 109 0x6d
VK_T 84 0x54
VK_TAB (\t) 9 0x9
VK_U 85 0x55
VK_UNDEFINED 0 0x0
VK_UP 38 0x26
VK_V 86 0x56
VK_W 87 0x57
VK_X 88 0x58
VK_Y 89 0x59
VK_Z 90 0x5a
Sun Ordering
name decimal hex
VK_ENTER (\n) 10 0xa
VK_BACK_SPACE (\b) 8 0x8
VK_TAB (\t) 9 0x9
VK_CANCEL 3 0x3
VK_CLEAR 12 0xc
VK_SHIFT 16 0x10
VK_CONTROL 17 0x11
VK_ALT 18 0x12
VK_PAUSE 19 0x13
VK_CAPS_LOCK 20 0x14
VK_ESCAPE 27 0x1b
VK_SPACE 32 0x20
VK_PAGE_UP 33 0x21
VK_PAGE_DOWN 34 0x22
VK_END 35 0x23
VK_HOME 36 0x24
VK_LEFT 37 0x25
VK_UP 38 0x26
VK_RIGHT 39 0x27
VK_DOWN 40 0x28
VK_COMMA 44 0x2c
VK_PERIOD 46 0x2e
VK_SLASH 47 0x2f
VK_0 48 0x30
VK_1 49 0x31
VK_2 50 0x32
VK_3 51 0x33
VK_4 52 0x34
VK_5 53 0x35
VK_6 54 0x36
VK_7 55 0x37
VK_8 56 0x38
VK_9 57 0x39
VK_SEMICOLON 59 0x3b
VK_EQUALS 61 0x3d
VK_A 65 0x41
VK_B 66 0x42
VK_C 67 0x43
VK_D 68 0x44
VK_E 69 0x45
VK_F 70 0x46
VK_G 71 0x47
VK_H 72 0x48
VK_I 73 0x49
VK_J 74 0x4a
VK_K 75 0x4b
VK_L 76 0x4c
VK_M 77 0x4d
VK_N 78 0x4e
VK_O 79 0x4f
VK_P 80 0x50
VK_Q 81 0x51
VK_R 82 0x52
VK_S 83 0x53
VK_T 84 0x54
VK_U 85 0x55
VK_V 86 0x56
VK_W 87 0x57
VK_X 88 0x58
VK_Y 89 0x59
VK_Z 90 0x5a
VK_OPEN_BRACKET 91 0x5b
VK_BACK_SLASH 92 0x5c
VK_CLOSE_BRACKET 93 0x5d
VK_NUMPAD0 96 0x60
VK_NUMPAD1 97 0x61
VK_NUMPAD2 98 0x62
VK_NUMPAD3 99 0x63
VK_NUMPAD4 100 0x64
VK_NUMPAD5 101 0x65
VK_NUMPAD6 102 0x66
VK_NUMPAD7 103 0x67
VK_NUMPAD8 104 0x68
VK_NUMPAD9 105 0x69
VK_MULTIPLY 106 0x6a
VK_ADD 107 0x6b
VK_SEPARATER 108 0x6c
VK_SUBTRACT 109 0x6d
VK_DECIMAL 110 0x6e
VK_DIVIDE 111 0x6f
VK_F1 112 0x70
VK_F2 113 0x71
VK_F3 114 0x72
VK_F4 115 0x73
VK_F5 116 0x74
VK_F6 117 0x75
VK_F7 118 0x76
VK_F8 119 0x77
VK_F9 120 0x78
VK_F10 121 0x79
VK_F11 122 0x7a
VK_F12 123 0x7b
VK_DELETE (ASCII del) 127 0x7f
VK_NUM_LOCK 144 0x90
VK_SCROLL_LOCK 145 0x91
VK_PRINTSCREEN 154 0x9a
VK_INSERT 155 0x9b
VK_HELP 156 0x9c
VK_META 157 0x9d
VK_BACK_QUOTE 192 0xc0
VK_QUOTE 222 0xde
VK_FINAL 24 0x18
VK_CONVERT 28 0x1c
VK_NONCONVERT 29 0x1d
VK_ACCEPT 30 0x1e
VK_MODECHANGE 31 0x1f
VK_KANA 21 0x15
VK_KANJI 25 0x19
VK_UNDEFINED 0 0x0
CHAR_UNDEFINED 0 0x0

Event vs. AWTEvent

In JDK 1.0.2 there was basically only one kind of Event, called the java.awt.Event. In JDK 1.1 there is a base Event called a java.awt.event.AWTEvent. All the other types of Event such as java.awt.event.actionEvent and java.awt.event.WindowEvent are derived from it. It is a bit confusing since the Event package for JDK 1.1 is called java.awt.event instead of java.awt.AWTEvent as you might expect.

Synthetic Events

There are a number of ways to fake an event.
  1. Check out Sun’s java.awt.Robot class for generating simulated keystrokes and mouse moves.
  2. The simplest is just to call a Listener method directly with a dummy Event object, filled in with just enough data to keep the method happy.
  3. Create an Event and introduce it to the Component that will handle it at the processEvent method. with:
  4. Create an Event and introduce it to the SystemEventQueue with:
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent( Event e );
  5. Generating MouseMoved Events has no effect on the screen mouse cursor. To make the underlying native GUI see your generated Events, use the Robot class to generate move clicks, moves etc.
    // synthetic native gui events
    import java.awt.event.InputEvent;
    import java.awt.event.KeyEvent;
    import java.awt.Robot;
    ...
    Robot r = new Robot();
    r.mouseMove( 100, 100 );
    r.keyPress( KeyEvent.VK_A );
    r.mousePress( InputEvent.BUTTON1_MASK );

Changes from JDK 1.0

In addition to the complete revamping of how it works inside, some of the interfacing details have changed too. The names of the various Events no longer live in the Event class. They live in the various subclasses of AWTEvent e.g. WindowEvent.WINDOW_CLOSED. Some Events have been renamed. WINDOW_DESTROY is now WINDOW_CLOSED. You can no longer access the source and id fields of an Event directly. You must call getSource and getID. handleEvent is now called processEvent. See my essay on JDK 1.0 events, primarily now of historical interest.

Changes with JDK 1.3

Starting with JDK 1.3 it is possible to insert custom Events into the system Event queue with awt.EventQueue.invokeLater( Runnable r ) (or invokeAndWait). It also appears to be possible to take direct control of the Event queue by sub-classing it using getToolkit().getSystemEventQueue().push( subclass of awt.EventQueue). You could then add some monitoring debug code for example.

The catch is MouseEvents you create this way don’t move the mouse cursor. To insert native events that will, see the Robot class. It can also be used to generate synthetic keystroke events. The Robot class helps you create self running demos.

Repaint

You may have seen mention of PaintEvent.PAINT and PaintEvent.UPDATE events. These are used to control how components are repainted. The repaint mechanism partly uses the SystemEventQueue and partly the queue inside the native GUI. See repaint in the Java & Internet Glossary for details on how it works.

Credits

This article would not have been possible without the patient assistance of Jan Newmarch who researched the material.
book_cover recommend book⇒Tricks Of The Java Programing Gurus
 paperback
ISBN10:1-57521-102-5
ISBN13:978-1-57521-102-2
publisher:Sams
published:1996-07
by:Glenn L. Vanderburg
Chapter by Jan Newmarch
Canadian flag amazon.ca. amazon.com. American flag
Canadian flag chapters.indigo.ca . powells.com American flag
French flag amazon.fr. barnesandnoble.com American flag
German flag amazon.de. amazon.co.uk. UK flag
Richard Baldwin and Peter Mehlitz helped explain the JDK 1.1+ event processing. Steve Odendahl pointed out the mismatched signature problem in Adapters. Tuyen Tran pointed out the problems with Swing and threading.

Summary

The key point to understand is that a component has two kinds of acceptor routines for Events. The generic processEvent routine primarily accepts events coming indirectly from the native GUI which it then fobs off on the more specific processXXXXEvent methods. The listener methods, e.g. actionPerformed, accept Events from other components. The listener methods are primarily for application programmers and those who customise existing components; the processXXXXEvent methods are primarily for the writers of radically new components.


CMP_homejump to top
CMP logo
feedback Please email your feedback for publication, errors, omissions, broken/redirected link reports
and suggestions to improve this page to Roedy Green : feedback email
made with CSS
HTML Checked!
ICRA ratings logo
mindprod.com IP:[65.110.21.43]
Your face IP:[38.103.63.17] The information on this page is for non-military use only.
You are visitor number 61,683. Military use includes use by defence contractors.
You can get a fresh copy of this page from: or possibly from your local J: drive (Java virtual drive/Mindprod website mirror)
http://mindprod.com/jgloss/event11.html J:\mindprod\jgloss\event11.html