KeyListener insensible à JFrame

J’essaie d’implémenter un KeyListener pour mon JFrame . Sur le constructeur, j’utilise ce code:

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

Lorsque je l’exécute, le message de test s’affiche dans ma console. Cependant, lorsque j’appuie sur une touche, je ne reçois aucun des autres messages, comme si KeyListener n’était même pas là.

Je pensais que cela pourrait être parce que l’accent n’est pas sur le JFrame
et ainsi KeyListener ne reçoit aucun événement. Mais je suis sûr que c’est le cas.

Y a-t-il quelque chose qui me manque?

Vous devez append votre keyListener à chaque composant dont vous avez besoin. Seul le composant avec le focus enverra ces événements. Par exemple, si vous n’avez qu’une seule zone de texte dans votre JFrame, cette zone de texte a le focus. Vous devez donc également append un KeyListener à ce composant.

Le processus est le même:

 myComponent.addKeyListener(new KeyListener ...); 

Remarque: Certains composants ne peuvent pas être focalisés comme JLabel.

Pour les régler sur focusable, vous devez:

 myComponent.setFocusable(true); 

Si vous ne souhaitez pas enregistrer un auditeur sur chaque composant,
vous pouvez append votre propre KeyEventDispatcher au 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(Ssortingng[] args) { MyFrame f = new MyFrame(); f.pack(); f.setVisible(true); } } 

Les InputMaps et ActionMaps ont été conçus pour capturer les événements clés du composant, de ses sous-composants et de la fenêtre entière. Ceci est contrôlé par le paramètre dans JComponent.getInputMap (). Voir Comment utiliser les liaisons de clé pour la documentation.

La beauté de cette conception réside dans le fait que l’on peut choisir les touches qui sont importantes à surveiller et que différentes actions sont déclenchées en fonction de ces touches.

Ce code appelle disposer () sur un JFrame lorsque la touche d’échappement est appuyée n’importe où dans la fenêtre. JFrame ne dérive pas de JComponent, vous devez donc utiliser un autre composant dans JFrame pour créer la liaison de clé. Le volet de contenu peut être un tel composant.

 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 est de bas niveau et ne s’applique qu’à un seul composant. Malgré des tentatives pour le rendre plus utilisable, JFrame crée un certain nombre de composants, le plus évident étant le volet de contenu. JComboBox UI est également souvent implémenté de manière similaire.

Il convient de noter que les événements de la souris fonctionnent d’une manière étrange, légèrement différente des événements clés.

Pour plus de détails sur ce que vous devez faire, consultez ma réponse sur le raccourci clavier Application large – Java Swing .

J’ai eu le même problème jusqu’à ce que je découvre que le véritable problème concerne FOCUS, votre JFrame a déjà ajouté des Listeners, mais que JFrame contient beaucoup de composants qui peuvent être focalisés, alors essayez:

 JFrame.setFocusable(true); 

Bonne chance

Deion (et quiconque pose une question similaire), vous pouvez utiliser le code de Peter ci-dessus, mais au lieu d’imprimer sur une sortie standard, vous testez le code de clé PRESSED, RELEASED ou 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; } 

Pour capturer les événements clés de TOUS les champs de texte dans un JFrame , on peut utiliser un post-processeur d’événement clé. Voici un exemple de travail, après avoir ajouté les inclusions évidentes.

 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(Ssortingng[] 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; } } 

Hmm .. quelle classe est votre constructeur? Probablement une classe qui étend JFrame? Le focus de la fenêtre devrait être à la fenêtre, bien sûr, mais je ne pense pas que ce soit le problème.

J’ai étendu votre code, essayé de l’exécuter et cela a fonctionné – les pressions sur les touches ont résulté en sortie d’impression. (exécuté avec Ubuntu via Eclipse):

 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(Ssortingng[] args) { MyFrame f = new MyFrame(); f.pack(); f.setVisible(true); } } 

Cela devrait aider

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

J’ai eu le même problème. J’ai suivi les conseils de Bruno et constaté que l’ajout d’un KeyListener au “premier” bouton du JFrame (c’est-à-dire en haut à gauche) faisait l’affaire. Mais je suis d’accord avec vous, c’est une sorte de solution troublante. Alors j’ai sortingpoté et découvert une meilleure façon de le réparer. Ajoutez simplement la ligne

 myChildOfJFrame.requestFocusInWindow(); 

à votre méthode principale, après avoir créé votre instance de votre sous-classe de JFrame et l’avez définie.

lol …. tout ce que vous avez à faire est de vous assurer que

addKeyListener (this);

est placé correctement dans votre code.

Vous pouvez faire en sorte que les composants JCompon personnalisés définissent leur parent JFrame focusable.

Ajoutez simplement un constructeur et transmettez le JFrame. Ensuite, appelez setFocusable () dans paintComponent.

De cette manière, JFrame recevra toujours des KeyEvents, que les autres composants soient ou non pressés.