You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActionListener内嵌KeyListener失效:迷宫游戏方向键无响应求助

解决迷宫游戏的两个问题:方向键无响应与按钮保持按下状态

嘿,我帮你分析下你遇到的问题,其实这俩问题根源是同一个,再加上个小的焦点问题,咱们一步步来解决:

问题根源拆解

当你点击主菜单按钮时,按钮的actionPerformed方法是在**Swing事件调度线程(EDT)**里执行的,但你直接调用了runner.run()——这个方法里有个持续的while(!win)循环,直接把EDT卡死了:

  1. 主菜单的UI更新全靠EDT,它被卡住后就没法刷新按钮状态,所以按钮一直保持按下;
  2. 迷宫窗口的键盘事件处理也依赖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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:06:27