For a program, I was using a KeyListener to add something to an ArrayList when pressing the button '1'. Objects in this list are being visualised constantly. With the KeyListener, this worked fluently, even when keeping the button pressed.
Later, I added a JMenuBar to the GUI. Adding something to the ArrayList now has an own JMenuItem with its accelerator set to the KeyStroke '1' and an ActionListener which performs the same stuff than the KeyListener before. However, the performance now is very bad. Keeping '1' pressed is going to lag extremely, it's very slow compared to the KeyListener.
Why is it so slow? Am I doing something wrong? Is there a better way?
...
AL al = new AL();
menu.add(createMenuItem("Add", KeyEvent.VK_1, al));
}
private JMenuItem createMenuItem(String text, int key, ActionListener al){
JMenuItem menuItem = new JMenuItem(text);
menuItem.setAccelerator(KeyStroke.getKeyStroke(key, 0));
menuItem.addActionListener(al);
return menuItem;
}
private class AL implements ActionListener{
public void actionPerformed(ActionEvent e){
int keycode = ((JMenuItem)e.getSource()).getAccelerator().getKeyCode();
bla(keycode);
}
}
It looks like the slowdown is how the menu accelerators are handled. It might be L&F or even OS since when I profile it, there is no hotspot in the Java code (WindowsXP) dependent. A workaround could be to add the key binding to the root pane instead of using an menu accelerator.
Press '1' to trigger KeyListener on button (fast) Press '2' to trigger menu accelerator (slow) Press '3' to trigger KeyBinding on button (fast) Press '4' to trigger KeyBinding on root pane (fast)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
public class TestKeySpeed {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
final JTextArea area = new JTextArea(20, 40);
area.setEditable(false);
JButton button = new JButton("Just something that has focus");
button.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_1) {
area.append("1");
}
}
});
AbstractAction action = new AbstractAction("Add") {
{
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke('2'));
}
@Override
public void actionPerformed(ActionEvent e) {
area.append("2");
}
};
button.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke('3'), "add3");
button.getActionMap().put("add3", action);
JMenu menu = new JMenu("File");
menu.add(action);
JMenuBar bar = new JMenuBar();
bar.add(menu);
JFrame frame = new JFrame("Test");
frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke('4'), "add4");
frame.getRootPane().getActionMap().put("add4", action);
frame.setJMenuBar(bar);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(area));
frame.getContentPane().add(button, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
button.requestFocusInWindow();
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With