Manu
Manu

Reputation: 65

Action / Keylisteners do not work properly

I have two frames (One main and one popup). On the main frame key & mouse listeners are added. Both work just fine. On the pop up there are 50 buttons. I have one action listener for all of them. It works fine. I also have key & mouse listeners. Mouse works. Key is flaky. The same keyListener class used in main frame is added to the pop-up frame too. As soon as the pop up shows, key listener works, once mouse click happens (Action listener kicks in) keylistener stops working. Please help. The code attached is a simplified version


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class key {
    private static  class toolsAction implements ActionListener {
        public void actionPerformed (ActionEvent ae) {
            log("Command " + Integer.parseInt(ae.getActionCommand()));
        }
    }
    private static void log(String s) { System.out.println(s); }
    private static class keyboardHandler implements KeyListener {
        public void keyPressed( KeyEvent e) { log("KB Press called ");   }
        public void keyReleased(KeyEvent e) { log("KB Release called "); }
        public void keyTyped   (KeyEvent e) { log("KB Typed called ");   }
    }
    public static void main(String [] args) {
        JFrame pFrame = new JFrame("Frame");
        pFrame.addKeyListener(new keyboardHandler());
        Container pane = pFrame.getContentPane();
        pane.setLayout(null);
        pane.setVisible(true);
        pFrame.setSize(650, 300);
        pFrame.setVisible(true);
        JButton[] buttons = new JButton[50];
        toolsAction action = new toolsAction();
        for (int i = 0; i < 50; i++) {
            buttons[i] = new JButton("" + i);
            buttons[i].setActionCommand("" + i);
            buttons[i].addActionListener(action);
            pane.add(buttons[i]);
            buttons[i].setBounds(((i % 10) * 60), ((i / 10) * 40), 60, 40);
        }
    }
}

Upvotes: 1

Views: 749

Answers (3)

Manu
Manu

Reputation: 65

I solved this problem by adding MouseMotionListener and in the mouseMoved method calling pFrame.requestFocusInWindow() & also adding focus request in the button's actionPerformed method. Even with just one button in a frame as long as the ActionListener is added to the button, KeyListener does not work. This is kludgy at best, but works for me. I would still love to hear from the community why my original code does not work.

Upvotes: 1

trashgod
trashgod

Reputation: 205785

An alternative approach uses Action and key bindings. The example below binds 10 buttons to the number keys, also using the numbers as the MNEMONIC_KEY of each.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/** @see http://stackoverflow.com/a/14182227/230513 */
public class Key {

    public static final int SIZE = 10;

    private static class ToolAction extends AbstractAction {

        public ToolAction(int i) {
            super(String.valueOf(i));
            putValue(MNEMONIC_KEY, KeyEvent.VK_0 + i);
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            System.out.println(ae.getActionCommand());
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame("Frame");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setLayout(new GridLayout(0, SIZE / 2));
                for (int i = 0; i < SIZE; i++) {
                    final ToolAction toolAction = new ToolAction(i);
                    JButton b = new JButton(toolAction);
                    String name = b.getText();
                    b.getInputMap(JButton.WHEN_IN_FOCUSED_WINDOW).put(
                        KeyStroke.getKeyStroke(KeyEvent.VK_0 + i, 0), name);
                    b.getActionMap().put(name, toolAction);
                    f.add(b);
                }
                f.pack();
                f.setVisible(true);
            }
        });
    }
}

Upvotes: 4

user85421
user85421

Reputation: 29680

The KeyListener will only be executed if the component, to which the listener is added, has the (keyboard) focus. If you click on another component, that component will become the focus and the keyboard events will be sent to its KeyListeners.
Not sure if that is the problem without seeing the code of the popup, but it's the problem in the posted code...

EDIT
you can add an AWTEventListener to the Toolkit to intercept all events independently of the focused component:

private static class AWTListener implements AWTEventListener {
    @Override
    public void eventDispatched(AWTEvent event) {
        log("AWT: " + event);
    }
};

...

    Toolkit toolkit = Toolkit.getDefaultToolkit();
    toolkit.addAWTEventListener(new AWTListener(), AWTEvent.KEY_EVENT_MASK);

Upvotes: 2

Related Questions