【问题标题】:Java Swing - ActionListener much slower than KeyListenerJava Swing - ActionListener 比 KeyListener 慢得多
【发布时间】:2012-03-08 17:46:02
【问题描述】:

对于一个程序,我在按下按钮“1”时使用 KeyListener 向 ArrayList 添加一些内容。此列表中的对象不断被可视化。使用 KeyListener,即使在按住按钮的情况下也能流畅地工作。

后来,我在 GUI 中添加了一个 JMenuBar。向 ArrayList 添加内容现在有一个自己的 JMenuItem,其加速器设置为 KeyStroke '1' 和一个 ActionListener,它执行与之前的 KeyListener 相同的内容。但是,现在的表现非常糟糕。按住“1”会非常滞后,与 KeyListener 相比非常慢。

为什么这么慢?难道我做错了什么?有没有更好的办法?

    ...
    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);
    }
}

【问题讨论】:

  • 你的keyPressed(keycode); 代码应该做什么?
  • 它是通过触发关键监听器来做到这一点的吗?
  • 来个SSCCE sscce.org
  • 是的,我同意提出 SSCCE 的建议。我们大多数人在使用 ActionListener 时都没有遇到“延迟”问题,这使得您使用 ActionListener 不太可能成为问题的根源,更有可能是您的代码发生了其他事情。什么?我不知道,sscce 可以提供帮助。请在回复之前检查链接,因为对于我们所要求的内容存在很多误解,链接已清除。
  • 我不知道,因为我没有可以运行、测试、修改和检查的代码。我不知道你在这里回答问题有多久了,但如果你回答了任何时间,你会迅速改变对 sscce 的价值的看法。这取决于您,取决于您真正需要我们帮助的程度。

标签: java swing


【解决方案1】:

看起来减速是菜单加速器的处理方式。它可能是 L&F 甚至操作系统,因为当我对其进行分析时,Java 代码 (WindowsXP) 依赖中没有热点。一种解决方法是将键绑定添加到根窗格,而不是使用菜单加速器。

按“1”在按钮上触发 KeyListener(快速) 按“2”触发菜单加速器(慢) 按“3”触发按键绑定(快速) 按“4”在根窗格上触发 KeyBinding(快速)

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();
            }
        });
    }
}

【讨论】:

  • 哇,这正是我想要的,非常感谢您的回答。您的 SSCCE 甚至比我尝试做的要好得多;)所以我通过使用菜单的菜单加速器以及 JPanel 上的 KeyBindings 使我的东西按我的预期工作(尽管两者的操作相同)。
  • '2' 在 Win7 上也很慢。显然,它取决于操作系统。
  • @Morrow:很高兴你有一个解决方案(Walter 是一个聪明的家伙,1 岁以上),但考虑一下 -- 必须创建一个 SSCCE 才能提出并测试解决方案,因此您会看到 SSCCE 对于提供解决方案是多么必要,无论是您还是他制定的。如果您先完成此操作,您会为他节省 很多 额外的工作,而他真的不需要在这些工作上浪费时间,而且您会更快地找到解决方案。这里的症结在于,这是您的问题,因此努力使我们能够更轻松地为您提供帮助的责任应该由您自己承担,而不是由 Walter 承担。
  • 很抱歉打死马,但正如你所知,这是我非常强烈的感受。我是 SSCCE 宗教的传教者。我再次为你感到高兴,很高兴从沃尔特那里学到了另一件新东西。
  • 我知道这一点并道歉,我真的无意将工作转移给其他人!当我发布这个问题时,我实际上认为这个问题是这里的“专业人士”会知道的,并且有人可以很容易地告诉我必须做什么。因此,我一开始并没有提出 SSCCE。
【解决方案2】:

其他因素正在减慢您的应用程序。这个example 仍然响应十几个Key Bindings。一种有用的方法是让菜单项和其他组件共享相同的actions,如herehere 所示。

附录:不实现ActionListener,而是通过扩展AbstractAction实现Action,这样可以更轻松地管理加速键。

【讨论】:

  • 嗯,我的问题不是由于几个键绑定导致的无响应,而是由于用 JMenuItem 加速器+ActionListener 替换了(完美工作的)KeyListener。我明天会发布一个SSCCE,我希望它会有所帮助。到目前为止谢谢!
  • @Morrow:很抱歉造成混乱;菜单在内部使用键绑定来实现加速器。当您的sscce 存在时,请在评论中联系我。
  • 很抱歉,我昨天没有得到您的答复,尽管这本来是我正在寻找的解决方案。 Walter Laan 已经提供了一个很好的例子。还是谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
相关资源
最近更新 更多