JFrameの応答しないKeyListener
-
08-07-2019 - |
質問
JFrame
に KeyListener
を実装しようとしています。コンストラクターでは、次のコードを使用しています:
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
はイベントを受け取りません。しかし、私はそれがかなり確信しています。
不足しているものはありますか?
解決
必要なすべてのコンポーネントにkeyListenerを追加する必要があります。フォーカスがあるコンポーネントのみがこれらのイベントを送信します。たとえば、JFrameにTextBoxが1つしかない場合、そのTextBoxにフォーカスがあります。したがって、このコンポーネントにもKeyListenerを追加する必要があります。
プロセスは同じです:
myComponent.addKeyListener(new KeyListener ...);
注:一部のコンポーネントは、JLabelのようにフォーカス可能ではありません。
それらをフォーカス可能に設定するには、以下を行う必要があります:
myComponent.setFocusable(true);
他のヒント
すべてのコンポーネントにリスナーを登録したくない場合は、
独自の 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);
}
}
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);
KeyListener
は低レベルであり、単一のコンポーネントにのみ適用されます。 JFrame
をより使いやすくしようと試みても、多くのコンポーネントコンポーネントが作成されますが、最も明白なのはコンテンツペインです。 JComboBox
UIも同様の方法で実装されることがよくあります。
マウスイベントは、キーイベントとは少し異なる奇妙な方法で機能することに注意してください。
あなたがすべきことの詳細については、アプリケーション全体のキーボードに関する回答をご覧ください。ショートカット-Java Swing 。
実際の問題は、JFrameがすでにリスナーを追加しているフォーカスに関するものであると読むまで、同じ問題が発生しましたが、JFrame内にフォーカス可能なコンポーネントがたくさんあるので、ツアーフレームは決してフォーカスされません。 / p>
JFrame.setFocusable(true);
幸運
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;
}
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;
}
}
うーん。どのクラスのコンストラクターですか?おそらく、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);
}
}
これは役立つはずです
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");
}
});
同じ問題を抱えています。ブルーノのアドバイスに従い、「最初の」だけにKeyListenerを追加することがわかりました。 JFrameのボタン(つまり、左上)がトリックを行いました。しかし、私はあなたにそれが一種の不安な解決策であることに同意します。だから私はいじってみて、それを修正するよりきれいな方法を発見しました。行を追加するだけ
myChildOfJFrame.requestFocusInWindow();
JFrameのサブクラスのインスタンスを作成して表示可能に設定した後、メインメソッドにします。
lol ....確認する必要があるのは
addKeyListener(this);
コード内に正しく配置されています。
カスタムJComponentsに親JFrameをフォーカス可能に設定できます。
コンストラクタを追加して、JFrameを渡すだけです。次に、paintComponentでsetFocusable()を呼び出します。
これにより、他のコンポーネントが押されているかどうかに関係なく、JFrameは常にKeyEventsを受け取ります。