Pregunta

Estoy intentando implementar un KeyListener para mi JFrame . En el constructor, estoy usando este código:

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

Cuando lo ejecuto, aparece el mensaje test en mi consola. Sin embargo, cuando presiono una tecla, no recibo ninguno de los otros mensajes, como si el KeyListener ni siquiera estuviera allí.

Estaba pensando que podría ser porque el foco no está en el JFrame
y entonces KeyListener no recibe ningún evento. Pero estoy bastante seguro de que lo es.

¿Hay algo que me falta?

¿Fue útil?

Solución

Debe agregar su keyListener a cada componente que necesite. Solo el componente con el foco enviará estos eventos. Por ejemplo, si solo tiene un TextBox en su JFrame, ese TextBox tiene el foco. Por lo tanto, debe agregar un KeyListener a este componente también.

El proceso es el mismo:

myComponent.addKeyListener(new KeyListener ...);

Nota: Algunos componentes no son enfocables como JLabel.

Para configurarlos como enfocables, necesita:

myComponent.setFocusable(true);

Otros consejos

Si no desea registrar un oyente en cada componente,
podría agregar su propio KeyEventDispatcher al 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 y ActionMaps fueron diseñados para capturar los eventos clave para el componente, éste y todos sus subcomponentes, o la ventana completa. Esto se controla a través del parámetro en JComponent.getInputMap (). Consulte Cómo utilizar las asociaciones de teclas para obtener documentación.

La belleza de este diseño es que uno puede elegir qué pulsaciones de teclas son importantes para controlar y disparar diferentes acciones en función de esas pulsaciones de teclas.

Este código llamará a dispose () en un JFrame cuando se presione la tecla de escape en cualquier lugar de la ventana. JFrame no se deriva de JComponent, por lo que debe usar otro componente en JFrame para crear el enlace de clave. El panel de contenido podría ser un componente de este tipo.

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 es de bajo nivel y se aplica solo a un solo componente. A pesar de los intentos de hacerlo más utilizable, JFrame crea una serie de componentes, el más obvio es el panel de contenido. La interfaz de usuario JComboBox también se implementa a menudo de manera similar.

Vale la pena señalar que los eventos del mouse funcionan de una manera extraña ligeramente diferente a los eventos clave.

Para obtener detalles sobre lo que debe hacer, consulte mi respuesta en Teclado ancho de aplicación acceso directo - Java Swing .

Tengo el mismo problema hasta que leí que el problema real es sobre el ENFOQUE, su JFrame ya ha agregado oyentes, pero el marco del recorrido nunca está en foco porque tiene muchos componentes dentro de su JFrame que también son enfocables, así que intente:

JFrame.setFocusable(true);

Buena suerte

Deion (y cualquier otra persona que haga una pregunta similar), puede usar el código de Peter anterior, pero en lugar de imprimir en la salida estándar, prueba el código clave PRESIONADO, LIBERADO o TIPADO.

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

para capturar eventos clave de TODOS los campos de texto en un JFrame , uno puede emplear un procesador posterior de eventos clave. Aquí hay un ejemplo de trabajo, después de agregar los obvios incluye.

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

Hmm ... ¿para qué clase es tu constructor? Probablemente alguna clase extendiendo JFrame? El foco de la ventana debería estar en la ventana, por supuesto, pero no creo que ese sea el problema.

Expandí su código, intenté ejecutarlo y funcionó: las pulsaciones de teclas resultaron como salida de impresión. (ejecutar con Ubuntu a través de 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);
    }
}

Esto debería ayudar

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

He tenido el mismo problema. Seguí el consejo de Bruno para ti y descubrí que agregar un KeyListener solo al "primer" botón en el JFrame (es decir, en la parte superior izquierda) hizo el truco. Pero estoy de acuerdo con usted, es una especie de solución inquietante. Así que jugueteé y descubrí una forma más ordenada de arreglarlo. Solo agrega la línea

myChildOfJFrame.requestFocusInWindow();

a su método principal, después de haber creado su instancia de su subclase de JFrame y configurarla como visible.

jajaja .... todo lo que tienes que hacer es asegurarte de que

addKeyListener (esto);

se coloca correctamente en su código.

Puede hacer que los JComponents personalizados establezcan su JFrame principal enfocable.

Simplemente agregue un constructor y pase el JFrame. Luego haga una llamada a setFocusable () en paintComponent.

De esta forma, JFrame siempre recibirá KeyEvents independientemente de si se presionan otros componentes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top