Keylistener no funciona para JPanel
Estoy intentando hacer algo cuando se presiona una de las teclas de flecha usando KeyListener en mi clase JPanel. Aquí está mi código:
public class TestPanel extends JPanel implements KeyListener{
public TestPanel(){
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
Mi método principal agrega una nueva instancia de este panel a un marco y lo muestra. ¿Necesito agregar el keylistener al JFrame? En mi caso, esto sería difícil e ineficiente, por lo que me gustaría que funcione con este JPanel si es posible. ¿Alguien sabe qué estoy haciendo mal?
EDITAR: Código de combinaciones de teclas que tampoco funciona:
public class GamePanel extends JPanel implements ActionListener{
//Constructor
public GamePanel(){
setupKeyBinding();
this.setFocusable(true);
this.requestFocusInWindow();
}
private void setupKeyBinding() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = getInputMap(condition);
ActionMap actMap = getActionMap();
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
actMap.put("Left", new leftAction());
}
private class leftAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
System.out.println("test");
}
}
public void actionPerformed(ActionEvent e) {
//some other game info
}
}
¿Alguien puede decirme por qué esto tampoco funciona? (mi segundo oyente de acción es para otras cosas necesarias para mi juego)
Si buscas este problema, verás que se pregunta y se ha solucionado muchas veces.
- Los KeyListeners deben estar en el componente enfocado para funcionar. Una solución es darle el foco a su componente después de hacerlo enfocable primero.
- Sin embargo, lo mejor con diferencia es utilizar combinaciones de teclas. Google el tutorial sobre esto.
Eche un vistazo a mi respuesta a esta pregunta para obtener más información sobre esto, incluidos muchos de los detalles sangrientos.
Como referencia, he creado un ejemplo utilizando su enfoque; Si bien funciona, también sugiere un problema de enfoque en otra parte de su código. Las combinaciones de teclas evitan esto, como se muestra aquí .
Anexo: Aquí está mi enlace de claves de trabajo.
private static class TestPanel extends JPanel {
private static final String LEFT = "Left";
private Action left = new AbstractAction(LEFT) {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(LEFT);
}
};
private static final String RIGHT = "Right";
private Action right = new AbstractAction(RIGHT) {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(RIGHT);
}
};
public TestPanel() {
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
this.getActionMap().put(LEFT, left);
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
this.getActionMap().put(RIGHT, right);
}
}
SSCCE original:
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* @see https://stackoverflow.com/a/16531380/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TestPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class TestPanel extends JPanel implements KeyListener {
public TestPanel() {
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test().display();
}
});
}
}