views:

35

answers:

3

I have a custom component subclassed from JPanel, with a keyboard handler. My main application embeds this inside another JPanel. Now I want the parent JPanel to also respond to keystrokes, since there are some actions that need to be taken only when the component is focused, but which apply to the app as a whole, and not that component (e.g. when I hit Ctrl-R I want a separate status window to refresh itself, but only when my component has the keyboard focus.)

Right now I'm doing this by explicitly passing my constructor a handler that its KeyListener calls when it's done, but it would probably be cleaner to use swing's native way of doing things, if it has one. Is there any support for this sort of handler chaining up a container hierarchy? I've looked at the KeyboardFocusManager and the KeyEventHandler, but those seem to be global in scope, whereas I want something restricted to a single container that triggers only when one of its children has the keyboard focus.

A: 

If you're looking at only having an event fire when a particular component has focus, a better approach might be to use a FocusListener on the component and have it add/remove the KeyListener when the component gains/loses focus.

example:

FocusListener focusListener = new FocusListener() {
    public void focusGained(FocusEvent event) {
        event.getComponent().addKeyListener(keyListener);
    }

    public void focusLost(FocusEvent event) {
        event.getComponent().removeKeyListener(keyListener);
    }

};
BCunningham
+1  A: 

All InputEvents (of which KeyEvents are derived) propagate up the component heirarchy, staring with the component that has focus, and moving up to its parent until they get to the root of the hierarchy (basically the containing window).

If you want to prevent a particular event from being propagated up when a particular component has focus, calling consume() on the event will prevent it from being processed once your event handler is done.

example:

KeyListener listener = new KeyAdapter() {
   public void keyPressed(KeyEvent event) {
      //...do some processing...
      event.consume();
   }
};
BCunningham
i tried that and it doesn't work: http://pastebin.org/366275only the label's keylistener is triggered.
Martin DeMello
+1  A: 

You could also try adding a key binder to the component.

Here's a tutorial that will show you how to use key bindings. Key bindings allow you to assign particular components actions to perform when they have a certain kind of focus, and can be used on any object that extends JComponent. This can be used more widely amongst all JComponent's and supports different focus types, e.g. when the component solely has the focus or when its window has the focus. Adding and removing a key listener can cause little bugs to creep into your application, especially if the focus listener misfires, so be careful if you choose that route.

peppertherj
thanks, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT looks like exactly what I need
Martin DeMello