Why do KeyBindings, but not KeyListeners, detect ActionEvents in the following example?

75 views Asked by At

From a java textbook, I copied a program that lets users move a body of text around their screens, using their arrow keys. The program will only work on non-OSX operating systems (I confirmed this with my mac and, presumably, it ran on the computer of the java textbook writer). I found a resolution to this discrepancy (Java KeyEvents on Mac), which recommended that I use KeyBindings instead of ActionListeners to process the firing and listening of events, with the vague rationale that

Note: To define special reactions to particular keys, use key bindings instead of a key listener.

While my code now runs, I still don't understand the resolution's rationale. Why is it that KeyBindings, but not KeyListeners, detect Mac arrowkey commands? The arrowkey commands are not "special reactions" that involve multiple keys (like Shift + a + b).

This is a segment of what I copied, the code that used a KeyListener

addKeyListener(new KeyListener()
        {

            @Override
            public void keyReleased(KeyEvent e) {

                switch (e.getKeyCode())
                {
                    case KeyEvent.VK_DOWN: 
                        y -= 10;
                        break;
                    case KeyEvent.VK_UP: 
                        y += 10; 
                        break;

                    //.... more code

And a segment with KeyBindings

 class DownAction extends AbstractAction
    {

        @Override
        public void actionPerformed(ActionEvent e) {
            y += 10;
            repaint();
        }
    }

    class UpAction extends AbstractAction
    {

        @Override
        public void actionPerformed(ActionEvent e) {
            y -= 10;
            repaint();
        }
    }
        this.getInputMap().put(KeyStroke.getKeyStroke("DOWN"),"down");
        this.getActionMap().put("down", new DownAction ());
        this.getInputMap().put(KeyStroke.getKeyStroke("UP"),"up");
        this.getActionMap().put("up", new UpAction ());

        // this segment is within a class that extends JPane
1

There are 1 answers

0
trashgod On

With a key listener, "a component must have the keyboard focus." In contrast, key bindings "take the containment hierarchy into account." You may have encountered a platform-specific vagary in how the containment hierarchy is searched or how the focus subsystem works.

As a concrete example, LinePanel contains a ControlPanel containing a number of MoveButton instances. Each MoveButton has an Action that moves the line. The enclosing ControlPanel also gets a WHEN_IN_FOCUSED_WINDOW map entry that binds the matching arrow key to an Action that clicks the corresponding button. In this way, a particular arrow buttons displays visual feedback, even if another button has focus.