Frage Nicht reagierender KeyListener für JFrame


Ich versuche ein zu implementieren KeyListener für mein JFrame. Im Konstruktor verwende ich diesen 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"); }
});

Wenn ich es betreibe, ist das test Nachricht erscheint in meiner Konsole. Wenn ich jedoch eine Taste drücke, bekomme ich keine der anderen Nachrichten, als ob die KeyListener war nicht einmal da.

Ich dachte, dass es sein könnte, weil der Fokus nicht auf der JFrame
und so sie KeyListener empfängt keine Ereignisse. Aber ich bin mir ziemlich sicher, dass es so ist.

Gibt es etwas, das mir fehlt?


75
2017-11-13 10:17


Ursprung


Antworten:


Sie müssen Ihren keyListener zu jeder Komponente hinzufügen, die Sie benötigen. Nur die Komponente mit dem Fokus sendet diese Ereignisse. Wenn Sie beispielsweise nur eine TextBox in Ihrem JFrame haben, hat diese TextBox den Fokus. Sie müssen also auch dieser Komponente einen KeyListener hinzufügen.

Der Prozess ist der gleiche:

myComponent.addKeyListener(new KeyListener ...);

Hinweis: Einige Komponenten sind nicht fokussierbar wie JLabel.

Um sie fokussierbar zu setzen, müssen Sie:

myComponent.setFocusable(true);

46
2017-11-13 13:01



Wenn Sie keinen Listener für jede Komponente registrieren möchten,
du könntest füge dein eigenes hinzu KeyEventDispatcher zum 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);
    }
}

125
2017-09-04 14:09



InputMaps und ActionMaps wurden entwickelt, um die Schlüsselereignisse für die Komponente, für sie und alle ihre Unterkomponenten oder für das gesamte Fenster zu erfassen. Dies wird durch den Parameter in JComponent.getInputMap () gesteuert. Sehen Wie man Tastenbelegungen benutzt für die Dokumentation.

Das Schöne an diesem Design ist, dass man auswählen kann, welche Schlüsselstriche wichtig für die Überwachung sind und verschiedene Aktionen basierend auf diesen Schlüsselstrichen ausgelöst haben.

Dieser Code ruft dispose () auf einem JFrame auf, wenn der Escape-Schlüssel irgendwo im Fenster gedrückt wird. JFrame wird nicht von JComponent abgeleitet, daher müssen Sie eine andere Komponente im JFrame verwenden, um die Schlüsselbindung zu erstellen. Der Inhaltsbereich könnte eine solche Komponente sein.

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

15
2018-02-23 00:29



KeyListener ist Low-Level und gilt nur für eine einzelne Komponente. Trotz Versuchen, es brauchbarer zu machen JFrame erstellt eine Reihe von Komponentenkomponenten, die offensichtlichste ist der Inhaltsbereich. JComboBox UI wird oft auch auf ähnliche Weise implementiert.

Es ist erwähnenswert, dass die Mausereignisse auf seltsame Weise etwas anders als Schlüsselereignisse funktionieren.

Für Details darüber, was Sie tun sollten, lesen Sie meine Antwort auf Anwendungsbreite Tastaturkürzel - Java Swing.


10
2017-11-13 13:18



Ich habe das gleiche Problem, bis ich gelesen habe, dass das eigentliche Problem ist über FOCUS der Ihr JFrame bereits Listener hinzugefügt hat, aber Tour Frame ist nie auf Focus, weil Sie viele Komponenten in Ihrem JFrame haben, die auch fokussierbar sind.

JFrame.setFocusable(true);

Viel Glück


10
2018-04-27 15:30



Deion (und alle anderen, die eine ähnliche Frage stellen), könnten Sie Peters Code oben verwenden, aber anstatt auf die Standardausgabe zu drucken, testen Sie den Schlüsselcode PRESSED, RELEASED oder 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
2018-01-09 14:50



um wichtige Ereignisse aller Textfelder in a JFrame, man kann einen Schlüsselereignis-Postprozessor verwenden. Hier ist ein funktionierendes Beispiel, nachdem Sie die offensichtlichen Includes hinzugefügt haben.

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
2017-07-15 19:47



Hmm .. Für welche Klasse ist dein Konstruktor? Wahrscheinlich eine Klasse, die JFrame erweitert? Der Fensterfokus sollte natürlich am Fenster liegen, aber ich glaube nicht, dass das das Problem ist.

Ich habe Ihren Code erweitert, versucht, ihn auszuführen, und es hat funktioniert - die Tasten drücken sich als Druckausgabe. (mit Ubuntu durch Eclipse laufen):

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

3
2017-11-13 10:39