Ваша проблема, по-видимому, связана с KeyListener и Focus. Я собираюсь предложить альтернативную технику. Используйте InputMap / ActionMap для панели.
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
panel.getInputMap().put(us, "UP");
panel.getActionMap().put("UP", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
//call what ever
}
});
Когда я делаю это, мне не нужно запрашивать фокус, у меня есть JFrame и JPanel, пока JFrame находится в фокусе, тогда соответствующие действия запускаются клавишами.
Вот полный пример, который перемещает круг вокруг JPanel.
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.EventQueue;
import java.awt.Color;
import javax.swing.KeyStroke;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
public class BallGame{
int x;
int y;
JPanel panel = new JPanel(){
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawOval(x-5, y-5, 10, 10);
}
};
public void start(){
JFrame frame = new JFrame();
frame.add(panel);
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
KeyStroke us = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
KeyStroke ds = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false);
KeyStroke ls = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
KeyStroke rs = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
panel.getInputMap().put(us, "UP");
panel.getInputMap().put(ds, "DOWN");
panel.getInputMap().put(ls, "LEFT");
panel.getInputMap().put(rs, "RIGHT");
panel.getActionMap().put("UP", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
up();
}
});
panel.getActionMap().put("DOWN", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
down();
}
});
panel.getActionMap().put("LEFT", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
left();
}
});
panel.getActionMap().put("RIGHT", new AbstractAction(){
@Override
public void actionPerformed(ActionEvent evt){
right();
}
});
}
public void up(){
y = y - 5;
y = y<0? panel.getHeight() : y;
panel.repaint();
}
public void down(){
y = y + 5;
y = y>panel.getHeight() ? 0 : y;
panel.repaint();
}
public void left(){
x = x - 5;
x = x<0 ? panel.getWidth() : x;
panel.repaint();
}
public void right(){
x = x + 5;
x = x>panel.getWidth() ? 0 : x;
panel.repaint();
}
public static void main(String[] args){
BallGame bg = new BallGame();
EventQueue.invokeLater( bg::start );
}
}
Проверьте API, хотя вы можете настроить его, чтобы ловить модификаторы и когда для запуска действия. Если вы хотите контролировать, когда клавиша нажата и когда она отпущена, et c.