web-dev-qa-db-ja.com

JFrameの応答しないKeyListener

KeyListenerJFrameを実装しようとしています。コンストラクターでは、次のコードを使用しています。

System.out.println("test");
addKeyListener(new KeyListener() {
    public void keyPressed(KeyEvent e) { System.out.println( "tester"); }

    public void keyReleased(KeyEvent e) { System.out.println("2test2"); }

    public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});

実行すると、testメッセージがコンソールに表示されます。ただし、キーを押しても、KeyListenerが存在しないかのように、他のメッセージは表示されません。

私はそれがJFrameに焦点を合わせていないからかもしれないと考えていました
したがって、KeyListenerはイベントを受信しません。しかし、そうだと確信しています。

欠けているものはありますか?

77
Tomek

必要なすべてのコンポーネントにkeyListenerを追加する必要があります。フォーカスのあるコンポーネントのみがこれらのイベントを送信します。たとえば、JFrameにTextBoxが1つしかない場合、そのTextBoxにフォーカスがあります。そのため、このコンポーネントにもKeyListenerを追加する必要があります。

プロセスは同じです:

myComponent.addKeyListener(new KeyListener ...);

注:一部のコンポーネントは、JLabelのようにフォーカス可能ではありません。

それらをフォーカス可能に設定するには、以下を行う必要があります。

myComponent.setFocusable(true);
46
bruno conde

すべてのコンポーネントにリスナーを登録したくない場合は、
できます独自のKeyEventDispatcherKeyboardFocusManagerに追加:

public class MyFrame extends JFrame {    
    private class MyDispatcher implements KeyEventDispatcher {
        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("tester");
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                System.out.println("2test2");
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                System.out.println("3test3");
            }
            return false;
        }
    }
    public MyFrame() {
        add(new JTextField());
        System.out.println("test");
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}
126
Peter

InputMapsとActionMapsは、コンポーネント、そのコンポーネントとそのすべてのサブコンポーネント、またはウィンドウ全体の主要なイベントをキャプチャするように設計されました。これは、JComponent.getInputMap()のパラメーターを介して制御されます。ドキュメントについては、「 キーバインドの使用方法 」を参照してください。

この設計の利点は、監視するのに重要なキーストロークを選択し、それらのキーストロークに基づいて異なるアクションを起動できることです。

このコードは、エスケープキーがウィンドウのどこかでヒットすると、JFrameでdispose()を呼び出します。 JFrameはJComponentから派生しないため、JFrame内の別のコンポーネントを使用してキーバインディングを作成する必要があります。コンテンツペインはそのようなコンポーネントである場合があります。

InputMap inputMap; 
ActionMap actionMap;
AbstractAction action;
JComponent component;

inputMap  = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actionMap = component.getActionMap();

action    = new AbstractAction()
{
   @Override
   public void actionPerformed(ActionEvent e)
   {
      dispose();
   }
};

inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
actionMap.put("dispose", action);
16
Nathan

KeyListenerは低レベルであり、単一のコンポーネントにのみ適用されます。 JFrameをさらに使いやすくする試みにもかかわらず、多くのコンポーネントコンポーネントが作成されますが、最も明白なのはコンテンツペインです。 JComboBox UIも同様の方法で実装されることがよくあります。

マウスイベントは、キーイベントとは少し異なる奇妙な方法で動作することに注意してください。

あなたがすべきことの詳細については、 アプリケーション全体のキーボードショートカット-Java Swing

10

本当の問題はJFrameがすでにリスナーを追加しているフォーカスに関するものであると読むまで同じ問題を抱えていましたが、JFrame内にフォーカス可能な多くのコンポーネントがあるため、ツアーフレームはフォーカスされません。

JFrame.setFocusable(true);

幸運を

10
Ferkiros

Deion(および同様の質問をする他の人)は、上記のPeterのコードを使用できますが、標準出力に出力する代わりに、PRESSED、RELEASED、またはTYPEDのキーコードをテストします。

@Override
public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getID() == KeyEvent.KEY_PRESSED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_RELEASED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_TYPED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    }
    return false;
}
8
Daves

JFrameのすべてのテキストフィールドのキーイベントをキャプチャするために、キーイベントポストプロセッサを使用できます。明らかなインクルードを追加した後の例を次に示します。

public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
    public static final long serialVersionUID = 1L;

    public KeyListenerF1Demo() {
        setTitle(getClass().getName());

        // Define two labels and two text fields all in a row.
        setLayout(new FlowLayout());

        JLabel label1 = new JLabel("Text1");
        label1.setName("Label1");
        add(label1);

        JTextField text1 = new JTextField(10);
        text1.setName("Text1");
        add(text1);

        JLabel label2 = new JLabel("Text2");
        label2.setName("Label2");
        add(label2);

        JTextField text2 = new JTextField(10);
        text2.setName("Text2");
        add(text2);

        // Register a key event post processor.
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
                .addKeyEventPostProcessor(this);
    }

    public static void main(String[] args) {
        JFrame f = new KeyListenerF1Demo();
        f.setName("MyFrame");
        f.pack();
        f.setVisible(true);
    }

    @Override
    public boolean postProcessKeyEvent(KeyEvent ke) {
        // Check for function key F1 pressed.
        if (ke.getID() == KeyEvent.KEY_PRESSED
                && ke.getKeyCode() == KeyEvent.VK_F1) {

            // Get top level ancestor of focused element.
            Component c = ke.getComponent();
            while (null != c.getParent())
                c = c.getParent();

            // Output some help.
            System.out.println("Help for " + c.getName() + "."
                    + ke.getComponent().getName());

            // Tell keyboard focus manager that event has been fully handled.
            return true;
        }

        // Let keyboard focus manager handle the event further.
        return false;
    }
}
4
Hubert Kauker

うーん..あなたのコンストラクタはどのクラスですか?おそらく、JFrameを拡張するクラスですか?もちろん、ウィンドウのフォーカスはウィンドウにあるべきですが、それが問題だとは思いません。

私はあなたのコードを拡張し、それを実行しようとしましたが、うまくいきました-キーを押すと、印刷出力が生成されました。 (Eclipseを介してUbuntuで実行):

public class MyFrame extends JFrame {
    public MyFrame() {
        System.out.println("test");
        addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                System.out.println("tester");
            }

            public void keyReleased(KeyEvent e) {
                System.out.println("2test2");
            }

            public void keyTyped(KeyEvent e) {
                System.out.println("3test3");
            }
        });
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}
2
Touko

これは役立つはずです

    yourJFrame.setFocusable(true);
    yourJFrame.addKeyListener(new Java.awt.event.KeyAdapter() {


        @Override
        public void keyTyped(KeyEvent e) {
            System.out.println("you typed a key");
        }

        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println("you pressed a key");
        }

        @Override
        public void keyReleased(KeyEvent e) {
            System.out.println("you released a key");
        }
    });
2
Rahul

私は同じ問題を抱えています。ブルーノのアドバイスに従って、JFrameの「最初の」ボタン(つまり左上)にKeyListenerを追加するだけでうまくいくことがわかりました。しかし、私はあなたに同意します、それは一種の不安な解決策です。それで私はいじくり回し、それを修正するよりきれいな方法を発見しました。行を追加するだけです

myChildOfJFrame.requestFocusInWindow();

jFrameのサブクラスのインスタンスを作成して表示可能に設定した後、メインメソッドに追加します。

1
pocketdora