java - KeyListener no responde para JFrame
swing (12)
Estoy tratando de implementar 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 de test
en mi consola. Sin embargo, cuando KeyListener
una tecla, no obtengo 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 es así.
¿Hay algo que me falta?
Debe agregar su KeyListener a cada componente que necesita. Solo el componente con el foco enviará estos eventos. Por ejemplo, si tiene solo un TextBox en su JFrame, ese TextBox tiene el foco. Por lo tanto, debe agregar 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 para enfocarse necesitas:
myComponent.setFocusable(true);
Deion (y cualquier otra persona que haga una pregunta similar), puede usar el código de Peter anterior, pero en lugar de imprimir a la salida estándar, prueba el código de tecla PRESIONADO, LIBERADO o TIPIFICADO.
@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;
}
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 estado teniendo el mismo problema. Seguí el consejo de Bruno y descubrí que agregar un KeyListener solo al "primer" botón en el JFrame (es decir, en la esquina superior izquierda) hacía el truco. Pero estoy de acuerdo con usted, es una solución algo inquietante. Así que jugueteé y descubrí una manera más ordenada de arreglarlo. Solo agregue la línea
myChildOfJFrame.requestFocusInWindow();
a su método principal, después de haber creado su instancia de su subclase de JFrame y establecerlo visible.
Hmm ... ¿para qué clase es tu constructor? ¿Probablemente alguna clase que extienda JFrame? El foco de la ventana debe estar en la ventana, por supuesto, pero no creo que ese sea el problema.
Expandí tu código, traté de ejecutarlo y funcionó: las pulsaciones de teclas se obtuvieron como resultado 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);
}
}
InputMaps y ActionMaps fueron diseñados para capturar los eventos clave para el componente, él y todos sus subcomponentes, o toda la ventana. Esto se controla a través del parámetro en JComponent.getInputMap (). Consulte Cómo utilizar enlaces de teclas para obtener documentación.
La belleza de este diseño es que uno puede escoger y elegir qué trazos de tecla son importantes para monitorear y tener diferentes acciones disparadas basadas en esas teclas.
Este código invocará a disponer () en un JFrame cuando se toca 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 puede 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);
Puede tener JComponents personalizados para que su JFrame padre sea 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.
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);
}
}
Tengo el mismo problema hasta que leí que el problema real es acerca de ENFOQUE: su JFrame ya ha agregado Oyentes, pero el marco de recorrido nunca está en el Enfoque porque tiene muchos componentes dentro de su Marco J que también son enfocables, así que intente:
JFrame.setFocusable(true);
Buena suerte
jaja ... todo lo que tienes que hacer es asegurarte de que
addKeyListener (esto);
está colocado correctamente en tu código.
para capturar eventos clave de TODOS los campos de texto en un JFrame , se puede emplear un post procesador de eventos clave. Aquí hay un ejemplo de trabajo, después de agregar lo obvio 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;
}
}
KeyListener
es de bajo nivel y se aplica solo a un componente individual. 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. JComboBox
UI también se implementa a menudo de manera similar.
Vale la pena señalar que los eventos del mouse funcionan de una forma extraña y ligeramente diferente de los eventos clave.
Para obtener más información sobre lo que debe hacer, consulte mi respuesta sobre el método abreviado de teclado de aplicación: Java Swing .