Java CardLayout下如何让jPanel3获焦以激活KeyListener
问题:KeyListener按键无响应,焦点获取失败
在使用KeyListener实现屏幕元素交互(仅通过打印文本验证功能)时,出现按键无响应的问题。已确认Board类与Player类的KeyListener逻辑无误,排查后定位问题出在采用CardLayout布局的主Test类中,推测承载游戏内容的jPanel3未获得焦点。尝试过部分代码调整但未解决,现咨询如何让jPanel3及其内部组件获取焦点。
主类Test代码
import javax.swing.JFrame; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Test extends JFrame implements ActionListener { CardLayout crd; JButton btn1, btn2, btn3, btn4; Container cPane; JPanel cPanel = new JPanel(); JPanel jPanel1,jPanel2,jPanel3; Board board = new Board(); private int currCard = 1; GridBagConstraints c = new GridBagConstraints(); Test() { jPanel1 = new JPanel(); jPanel2 = new JPanel(); jPanel3 = new JPanel(); btn1 = new JButton("Start"); btn2 = new JButton("Help"); btn3 = new JButton("Back"); btn4 = new JButton("Exit"); cPane = getContentPane(); crd = new CardLayout(); cPanel.setLayout(crd); buttons(); panel1(); panel2(); panel3(); cPanel.add(jPanel1, "1"); cPanel.add(jPanel2, "2"); cPanel.add(jPanel3, "3"); btn1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { currCard = 3; crd.show(cPanel, "" + (currCard)); } }); btn2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { currCard = 2; crd.show(cPanel, "" + (currCard)); } }); btn3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { currCard = 1; crd.show(cPanel, ""+ (currCard)); } }); btn4.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { System.exit(0); } }); getContentPane().add(cPanel); } void panel1() { jPanel1.setBackground(Color.black); jPanel1.setLayout(new GridBagLayout()); // Set the layout to GridBagLayout c.fill = GridBagConstraints.CENTER; c.insets = new Insets(15, 0, 0, 0); // Add vertical padding jPanel1.add(btn1, c); c.gridy = 1; jPanel1.add(btn2, c); c.gridy = 2; jPanel1.add(btn4, c); } void panel2() { JTextArea textField = new JTextArea("Text text"); textField.setEditable(false); textField.setHighlighter(null); Font font = new Font("Courier", Font.BOLD, 35); textField.setFont(font); textField.setPreferredSize(new Dimension(500, 940)); textField.setForeground(Color.WHITE); textField.setBackground(Color.black); jPanel2.setBackground(Color.black); jPanel2.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTHWEST; // Align component to the upper left corner gbc.insets = new Insets(15, 0, 0, 0); // Add vertical padding gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1.0; // Expand horizontally gbc.weighty = 0.5; // Expand vertically jPanel2.add(textField, gbc); gbc.gridx = 0; gbc.gridy = 1; // Set the grid position for btn3 gbc.anchor = GridBagConstraints.NORTH; // Align component to the upper left corner jPanel2.add(btn3, gbc); } void panel3() { jPanel3.setFocusable(true); jPanel3.setRequestFocusEnabled(true); jPanel3.setLayout(new BorderLayout(0, 0)); jPanel3.add(board); jPanel3.grabFocus(); } void buttons() { // make the buttons look better and make it so they look good with the background, chane the size of them btn1.setPreferredSize(new Dimension(75, 50)); btn1.setBackground(Color.black); btn1.setForeground(Color.WHITE); btn2.setPreferredSize(new Dimension(75, 50)); btn2.setBackground(Color.black); btn2.setForeground(Color.WHITE); btn3.setPreferredSize(new Dimension(75, 50)); btn3.setBackground(Color.black); btn3.setForeground(Color.WHITE); btn4.setPreferredSize(new Dimension(75, 50)); btn4.setBackground(Color.black); btn4.setForeground(Color.WHITE); } public static void main(String argvs[]) { System.out.println("aaa" + System.getProperty("user.dir")); Test frame = new Test(); frame.setTitle("Space invaders"); frame.setSize(900, 900); frame.setVisible(true); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent arg0) { throw new UnsupportedOperationException("Unimplemented method 'actionPerformed'"); } }
Board类代码
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Stroke; import java.awt.event.KeyListener; import javax.swing.JPanel; public class Board extends JPanel { Player player = new Player(50, 50, 50, 50); public Board(){ addKeyListener((KeyListener) player); setFocusable(true); } public void paint(Graphics g) { g.setColor(Color.DARK_GRAY); g.fillRect(0, 0, 900, 900); g.setColor(Color.WHITE); g.drawRect (20, 20, 864, 624); g.setColor(Color.BLACK); g.fillRect (21, 21, 863, 623); g.setColor(Color.WHITE); g.setFont(new Font("arial",Font.PLAIN,14)); player.draw(g); //repaint(); } public void board(Graphics g) { Graphics2D g2d = (Graphics2D) g; Stroke stroke1 = new BasicStroke(4f); g2d.setColor(Color.white); g2d.setStroke(stroke1); g2d.drawRect(20, 50, 850, 600); g2d.setColor(Color.white); float[] dashingPattern2 = {10f, 4f}; Stroke stroke2 = new BasicStroke(4f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, dashingPattern2, 0.0f); g2d.setStroke(stroke2); g2d.drawLine(448, 50, 448, 650); g.setFont(new Font("arial",Font.PLAIN,30)); } }
Player类代码
import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JPanel; public class Player extends JPanel implements KeyListener { public int playerXpos; public int playerYpos; public int playerWidth; public int playerHeight; public int speed = 2; boolean down = false; boolean up = false; Rectangle player; public Player(int playerXpos, int playerYpos, int playerWidth, int playerHeight){ this.playerXpos = playerXpos; this.playerYpos = playerYpos; this.playerWidth = playerWidth; this.playerWidth = playerHeight; player = new Rectangle(playerXpos, playerYpos, playerWidth, playerHeight); } protected void draw(Graphics g) { playerXpos = 500; playerYpos = 60; playerWidth = 50; playerHeight = 30; g.setColor(Color.CYAN); g.fillRect(playerXpos, playerYpos, playerWidth, playerHeight); } @Override public void keyPressed(KeyEvent keyCode) { if (keyCode.getKeyCode() == KeyEvent.VK_UP) { System.out.println("Up Arrrow-Key is pressed!"); } else if (keyCode.getKeyCode() == KeyEvent.VK_DOWN) { System.out.println("Down Arrrow-Key is pressed!"); } else if (keyCode.getKeyCode() == KeyEvent.VK_LEFT) { System.out.println("Left Arrrow-Key is pressed!"); } else if (keyCode.getKeyCode() == KeyEvent.VK_RIGHT) { System.out.println("Right Arrrow-Key is pressed!"); } } @Override public void keyReleased(KeyEvent arg0) { throw new UnsupportedOperationException("Unimplemented method 'keyReleased'"); } @Override public void keyTyped(KeyEvent arg0) { throw new UnsupportedOperationException("Unimplemented method 'keyTyped'"); } }
解决方案
1. 切换卡片后主动请求焦点
grabFocus()在组件未显示时调用无效,必须在Card切换完成后,让实际承载KeyListener的Board组件请求焦点。修改btn1的ActionListener:
btn1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { currCard = 3; crd.show(cPanel, "" + (currCard)); // 卡片显示后,让Board组件请求焦点 board.requestFocusInWindow(); } });
2. 优化组件焦点设置
在Board类构造方法中添加setRequestFocusEnabled(true),确保组件可以主动获取焦点:
public Board(){ addKeyListener((KeyListener) player); setFocusable(true); setRequestFocusEnabled(true); }
3. 替换KeyListener为KeyBindings(推荐)
KeyListener对焦点依赖极强,Swing官方更推荐使用KeyBindings处理按键事件,无需组件获得焦点也能响应。修改Board类:
public Board(){ // 移除原KeyListener // addKeyListener((KeyListener) player); // 使用KeyBindings绑定方向键 InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); ActionMap actionMap = getActionMap(); // 绑定上箭头 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up"); actionMap.put("up", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Up Arrrow-Key is pressed!"); } }); // 绑定下箭头 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down"); actionMap.put("down", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Down Arrrow-Key is pressed!"); } }); // 同理绑定左右箭头... setFocusable(true); }
4. 修复Player类笔误
Player构造方法中this.playerWidth = playerHeight;是错误,应改为this.playerHeight = playerHeight;,否则会导致绘制的玩家矩形尺寸异常。
内容的提问来源于stack exchange,提问作者Jon doe
相关产品推荐
相关产品推荐

