web-dev-qa-db-fra.com

Unresponsive KeyListener pour 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 test apparaît dans ma console. Cependant, lorsque j'appuie sur une touche, aucun autre message ne s'affiche, comme si le KeyListener n'était même pas là.

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

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

77
Tomek

Vous devez ajouter 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 a le focus. Vous devez donc également ajouter un KeyListener à ce composant.

Le processus est le même:

myComponent.addKeyListener(new KeyListener ...);

Remarque: Certains composants ne peuvent pas être mis au point, comme JLabel.

Pour les définir sur focusable, vous devez:

myComponent.setFocusable(true);
46
bruno conde

Si vous ne voulez pas enregistrer un auditeur sur chaque composant,
vous pourriez ajouter votre propre KeyEventDispatcher à la 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);
    }
}
126
Peter

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

La beauté de cette conception réside dans le fait que l’on peut choisir quels coups de touche sont importants à surveiller et avoir différentes actions déclenchées en fonction de ces coups de touche.

Ce code appellera la disposition () sur une image 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);
16
Nathan

KeyListener est de bas niveau et ne s'applique qu'à un seul composant. Malgré les tentatives visant à le rendre plus utilisable, JFrame crée un certain nombre de composants, le plus évident étant le volet contenu. JComboBox UI est également souvent implémenté de la même manière.

Il est à noter que les événements de la souris fonctionnent d'une manière étrange légèrement différente de celle des événements clés.

Pour plus de détails sur ce que vous devez faire, voir ma réponse à la question Raccourci clavier à l'échelle de l'application - Java Swing .

10

J'ai eu le même problème jusqu'à ce que j'ai lu que le vrai problème concerne FOCUS, votre JFrame a déjà ajouté des auditeurs, mais le cadre de la tournée n'est jamais au point car vous avez beaucoup de composants dans votre JFrame qui peuvent également être mis au point. Essayez:

JFrame.setFocusable(true);

Bonne chance

10
Ferkiros

Deion (et toute autre personne posant 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;
}
8
Daves

afin de capturer les événements clés de TOUS les champs de texte dans un JFrame, on peut employer un post-processeur d’événements clés. Voici un exemple de travail, après avoir ajouté l'évidence inclut.

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

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 développé votre code, essayé de l'exécuter et cela a fonctionné - les pressions sur les touches résultent en une sortie imprimée. (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(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}
2
Touko

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

J'ai eu le même problème. J'ai suivi le conseil 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 en quelque sorte une solution déroutante. J'ai donc bricolé et découvert un moyen plus ordonné de le réparer. Il suffit d'ajouter la ligne

myChildOfJFrame.requestFocusInWindow();

à votre méthode principale, après avoir créé votre instance de votre sous-classe de JFrame et l'avoir rendue visible.

1
pocketdora