ActionListener内嵌KeyListener失效:迷宫游戏方向键无响应求助
解决迷宫游戏的两个问题:方向键无响应与按钮保持按下状态
嘿,我帮你分析下你遇到的问题,其实这俩问题根源是同一个,再加上个小的焦点问题,咱们一步步来解决:
问题根源拆解
当你点击主菜单按钮时,按钮的actionPerformed方法是在**Swing事件调度线程(EDT)**里执行的,但你直接调用了runner.run()——这个方法里有个持续的while(!win)循环,直接把EDT卡死了:
- 主菜单的UI更新全靠EDT,它被卡住后就没法刷新按钮状态,所以按钮一直保持按下;
- 迷宫窗口的键盘事件处理也依赖EDT,阻塞后方向键的事件根本传不到
KeyListener里,自然没响应。
具体解决方案
1. 把迷宫运行逻辑放到独立线程中
不要直接调用runner.run()(这只是普通方法调用,不会开新线程),而是把MazeRunner作为Runnable放进新线程启动,让EDT能专心处理UI更新:
修改MainMenu里的playMaze方法:
public void playMaze(int i) throws FileNotFoundException{ MazeCreator creator = new MazeCreator(); creator.createMaze("MAZE" + i + ".txt"); MazeRunner runner = new MazeRunner(creator.getMaze(), 0, 5, timer); // 启动新线程跑迷宫逻辑,不占用EDT new Thread(runner).start(); // 单独开线程监听迷宫结束,然后回到EDT更新主菜单的计时器 new Thread(() -> { while(!runner.checkWin()){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } timer = runner.getTime(); // 必须在EDT里更新UI,避免线程安全问题 SwingUtilities.invokeLater(() -> Timer.setText("" + timer/10.0)); }).start(); }
2. 确保Canvas能获取键盘焦点
在MazeRunner的构造方法里,给Canvas加上可聚焦设置,再用更可靠的方式请求焦点:
public MazeRunner(String[][] Maze, int Y, int X, int t){ frame = new JFrame("Maze Game"); JPanel panel = (JPanel) frame.getContentPane(); panel.setPreferredSize(new Dimension(220, 250)); panel.setLayout(null); canvas = new Canvas(); canvas.setBounds(0, 0, 220, 250); canvas.setIgnoreRepaint(true); // 关键:让Canvas可以接收焦点 canvas.setFocusable(true); panel.add(canvas); canvas.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent evt) { move(evt); } }); // 改成DISPOSE_ON_CLOSE,关闭迷宫窗口不会退出整个程序 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.pack(); frame.setResizable(false); frame.setVisible(true); canvas.createBufferStrategy(2); bufferStrategy = canvas.getBufferStrategy(); // 用requestFocusInWindow比requestFocus更可靠 canvas.requestFocusInWindow(); maze = Maze; x = X; y = Y; maze[y][x] = "@"; win = false; timer = t; }
3. 给主菜单加个合理的关闭逻辑
在MainMenu的构造方法末尾加上:
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
这样关闭主菜单时会正常退出程序。
额外小建议
- 尽量别用
null布局管理Swing组件,主菜单可以用GridLayout或者BoxLayout,UI会更稳定; - Swing里的
Key Bindings比KeyListener更推荐,它能避开很多焦点相关的坑,你可以后续尝试替换; - 所有UI更新操作都要确保在EDT里执行,用
SwingUtilities.invokeLater()包裹,避免奇怪的线程问题。
内容的提问来源于stack exchange,提问作者Adam Howard
相关产品推荐
相关产品推荐

