Global Event Listeners
Posted by Rob Camick on August 30, 2009
Listeners are used to listen for specific events on a given component. This makes it easy to listen for a MouseEvent on a text component for example. With this approach you need to add a separate listener to the component for every event you want to listen for. However there may be times when you want to listen for events at a more global level. That is, you may want to listen for events:
- of multiple types on a specific component – in this case you would need to create multiple listeners to add to the component.
- of a single type on all components – in this case you would need to create a single listener and then recursively add it to all components.
Wouldn’t it be nice if the above requirements could be handled by a single listener?
The Swing tutorial does a good job of introducing the common event listeners used in Swing. However, it doesn’t even mention the most powerfull listener, the AWTEventListener. The AWTEventListner has the ability to listen for all events generated on all components. This listener is different from most listeners in that you control the events you want to listen for by specifying an event mask.
For example, to listen for all MouseEvents and KeyEvents in a application you can use:
long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK
Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
public void eventDispatched(AWTEvent e)
As this code executes on the Event Dispatch Thread you will need to make sure that it executes quickly to prevent the GUI from becoming unresponsive. The above approach was used in the Application Inactivity entry if you want to look at a working example.
Another more specific listener you might consider using is a PropertyChangeListener added to the KeyboardFocusManager. This listener will allow you to listen for various focus events (see the API for details). As a simple example, you might want to select the text every time a text field gets focus:
.addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()
public void propertyChange(final PropertyChangeEvent e)
if (e.getNewValue() instanceof JTextField)
// invokeLater needed for JFormattedTextField
public void run()
JTextField textField = (JTextField)e.getNewValue();
Another specific listener you might consider using is a KeyEventPostProcessor which is also added to the KeyboardFocusManager. This listener will allow you to listen for key events. Basic usage would be as follows:
KeyEventPostProcessor pp = new KeyEventPostProcessor()
public boolean postProcessKeyEvent(KeyEvent e)
The above examples show how you can do some basic filtering to listen for specific events on all components. When you require the events for a specific component, or group of components, then you will need to filter out the events you are interested in. A few ideas on how you might implement this. If you only need events for:
- a few specifc components – then you might create a Set containing these components so you can compare the source of each event
- a specific panel – then you could use SwingUtilities.isDescendingFrom(…) method to check if a component is a child of a given Component so you don’t need to create a Set of all the components.
- a given window – then you would add/remove the listener as the window is activated/deactivated by using a WindowListener
Hopefully, the above suggestions will help help the next time you are looking to handle events at a global level.