JFrameの応答しないKeyListener


80

私は自分のためにを実装しようとしKeyListenerていJFrameます。コンストラクターでは、次のコードを使用しています。

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おらず、イベントを受け取らないからかもしれないと思っていました。しかし、私はそれが正しいと確信しています。

足りないものはありますか?

回答:


51

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

プロセスは同じです:

myComponent.addKeyListener(new KeyListener ...);

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

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

myComponent.setFocusable(true);

2
そうです、プログラムが起動すると、ボタンAに焦点が当てられていることが少しわかります。各ボタンにキーリスナーを追加すると、これが修正されました。それは少し奇妙です。JFrameにキーリスナーを追加することはうまくいくと思いますが、そうではないと思います。ありがとう!
Tomek

キーボードからリッスンするリスナーをJFrameで作成しました。ウィンドウが正面にない(フォーカスされている)場合でも、パッシブモードで動作させたいです。JFrameはパッシブモードでリッスンしていません。
usman 2015

133

あなたはすべてのコンポーネントにリスナーを登録したくない場合、
あなたは可能性があなた自身を追加KeyEventDispatcherしますKeyboardFocusManager

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

5
KeyboardFocusManagerはアプリケーション全体です。複数のフレームがある場合、問題が発生しますか?
neoedmund 2013

2
したがって、これは次のように機能するはずです。foreach( "フレーム内のフォーカス可能なコンポーネント" as _){_。addkeylistener(frameKeylistener);}
neoedmund 2013

16

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

このデザインの優れている点は、監視するのに重要なキーストロークを選択して選択し、それらのキーストロークに基づいてさまざまなアクションを実行できることです。

このコードは、ウィンドウ内のどこかでEscキーが押されたときに、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);

10

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

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

何をすべきかについての詳細は、アプリケーション全体のキーボードショートカット-JavaSwingに関する私の回答を参照してください。


10

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

JFrame.setFocusable(true);

幸運を


2
これは、JFrameにあるものを使用するまでしか機能せず、KeyListenerが応答しなくなることが
わかりました

9

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

4

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

実用的な例として、インポートを追加することを検討してください。私は通常、それらを短くするために「パッケージインポート」を追加します。それ以外の場合は+1。面白いテクニック。
Andrew Thompson

2

うーん..コンストラクターはどのクラス用ですか?おそらく、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);
    }
}

すべてのメッセージも出力されます。Windowsコマンドラインで実行します。
ダレル

2
この例ではJFrameにフォーカスがあるため、すべてのメッセージが表示されます。JFrameにTextBoxコンポーネントを追加して、何が起こるかを確認してください。
bruno conde

2

これは役立つはずです

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

1

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

myChildOfJFrame.requestFocusInWindow();

JFrameのサブクラスのインスタンスを作成し、それを表示するように設定した後、メインメソッドに追加します。


おかげで、同じ問題がありました。奇妙なことに、それがコンテンツペインであっても、コンポーネントはフォーカスを失います...
アンドロビン2016

-3

笑....あなたがしなければならないのはそれを確認することだけです

addKeyListener(this);

コードに正しく配置されます。


8
これを役立つ答えにするために、「正しい場所」を本当に説明する必要があります。
ティル

-3

カスタムJComponentに、親JFrameをフォーカス可能に設定させることができます。

コンストラクターを追加して、JFrameを渡すだけです。次に、paintComponentでsetFocusable()を呼び出します。

このようにして、他のコンポーネントが押されているかどうかに関係なく、JFrameは常にKeyEventsを受信します。


4
-1絶対にそうではありません-それは複数の点で完全な<強い単語の検閲>です:a)
下品
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.