2012-03-08 23 views
2

プログラムの場合、KeyListenerを使用してボタン '1'を押したときに何かをArrayListに追加していました。このリストのオブジェクトは常に視覚化されています。 KeyListenerを使用すると、ボタンを押したままにしてもうまく機能しました。Java Swing - KeyListenerよりもはるかに低速のActionListener

後で、GUIにJMenuBarを追加しました。 ArrayListに何かを追加すると、アクセラレータがKeyStroke '1'に設定された独自のJMenuItemと以前にKeyListenerと同じものを実行するActionListenerが追加されました。しかし、パフォーマンスは非常に悪いです。 '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); 
    } 
} 
+0

あなたの 'keyPressed(keycode);'コードは何をすべきでしょうか? –

+0

私はこのメソッドを全く変更しませんでしたが、KeyListenerでうまく動作します。しかし、あなたの質問に答えるために、 (Keycode == KeyEvent.VK_1)の場合はArrayListにオブジェクトが追加され、== KeyEvent.VK_ESCAPEの場合はプログラムが終了します。 – Morrow

+1

これはキーリスナーをトリッピングすることで行いますか? –

答えて

5

メニューアクセラレータの処理方法が減速しているようです。私がそれをプロファイルするとき、Javaコード(WindowsXP)に依存しないホットスポットがあるので、それはL & FまたはOSでもあるかもしれません。回避策は、メニューアクセラレータを使用する代わりに、ルートペインにキーバインドを追加することです。上のキーバインドトリガする(高速)ボタンのKeyListenerをトリガする

押し「1」 (速い)ボタンキーバインドをトリガするメニューアクセラレータ(遅い) を押し「3」トリガするプレス「2」 押し「4」ルートペイン(速い)

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

うわー、これはまさに私が探していたものです。ありがとうございました。あなたのSSCCEは私がやろうとしていたよりもはるかに優れています;)メニューのアクセラレータとJPanelのKeyBindingsを使用することで、私の意図どおりに動作します。 – Morrow

+0

+1包括的です。 Mac OS Xでも同じように高速です。 – trashgod

+0

'2'もWin7では遅いです。明らかに、OSに依存します。 – Morrow

4

他の何かがあなたのアプリケーションを遅くしています。このexampleは12ダース以上の応答を維持しますKey Bindings。便利なアプローチの1つは、herehereのように、メニュー項目と他のコンポーネントが同じactionsを共有するようにすることです。

補足:ActionListenerを実装する代わりにAbstractActionを拡張してActionを実装すると、アクセラレータキーの管理が容易になります。

+0

私の問題は、いくつかのキーバインディングが原因ですが、(完璧に動作する)KeyListenerをJMenuItemアクセラレータ+ ActionListenerに置き換えることによって反応しません。私は明日SSCCEを掲示します、それが助けてくれることを願っています。今までありがとう! – Morrow

+0

@Morrow:混乱して申し訳ありません。メニューは内部でキーバインドを使用してアクセラレータを実装します。あなたの[sscce](http://sscce.org/)が現存している時に、私のコメントにお答えください。 – trashgod

+0

申し訳ありませんが、私が探していた解決策であったとしても、私はあなたの答えを昨日受け取っていませんでした。 Walter Laanはすでに素晴らしい例を提供しています。とにかくありがとう! – Morrow

関連する問題