Reputation: 65
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
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
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
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 KeyListener
s.
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