Java Tips Weblog

  • Blog Stats

    • 2,569,218 hits
  • Categories

  • Archives

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
    + AWTEvent.MOUSE_EVENT_MASK
    + AWTEvent.KEY_EVENT_MASK;

Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
    public void eventDispatched(AWTEvent e)
    {
        System.out.println(e.getID());
    }
}, eventMask);

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:

KeyboardFocusManager.getCurrentKeyboardFocusManager()
    .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()
{
    public void propertyChange(final PropertyChangeEvent e)
    {
        if (e.getNewValue() instanceof JTextField)
        {
            //  invokeLater needed for JFormattedTextField
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    JTextField textField = (JTextField)e.getNewValue();
                    textField.selectAll();
                }
            });
        }
    }
});

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) 
    {
        System.out.println(e);
        return true;
    }
};

DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager().
    addKeyEventPostProcessor(pp);

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.

See Also

Application Inactivity
Global Event Dispatching

Related Reading

Java Tutorials: Writing Event Listeners

13 Responses to “Global Event Listeners”

  1. Tbee said

    I use a similar technique (Toolkit.getDefaultToolkit().getSystemEventQueue()) to catch all system events and then display popup menu’s on all component (with copy, paste, etc).

  2. Paulo said

    How about keyeventpostprocessor?

  3. Puri said

    Very useful! Really help me.

  4. Nikhil said

    Thanks Rob, Its really very helpful information in very simple language. Best Regards.

  5. Dinesh Bajaj said

    Many thanks Rob for this post. This is what I was exactly looking for. :-)

  6. David Fagnan said

    Thanks Rob! I also found this post very helpful. I was not aware of these techniques.

  7. Amber R said

    This is so much easier than adding listeners to all the child components. Very helpful, thanks!

Leave a reply to Rob Camick Cancel reply