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

Java Swing问题:康威生命游戏JPanel更新世代时无法获取新值

问题排查与修复方案

核心故障原因

  1. 数组引用未同步
    构造PaintCells实例时,你将初始cells数组的引用传递给了PaintCells内部的newOriginalCells变量。后续在newGeneration()中执行cells = newCells时,仅修改了GameOfLife类中cells变量的指向,PaintCells内部存储的数组引用仍然指向旧数组,因此绘制时永远读取的是初始数据,不会更新。
  2. Swing事件调度线程被阻塞
    按键事件的回调、界面重绘都运行在Swing专属的事件调度线程(EDT)中。你在newGeneration()中使用Thread.sleep()+递归无限调用的逻辑,直接占满了EDT线程,repaint()请求根本没有机会被执行,界面会完全卡住。

修复方案

1. 同步绘制面板的细胞数组

给PaintCells类新增数组更新方法,每次世代计算完成后同步更新面板内部存储的数组引用,同时建议自定义绘制重写paintComponent而非paint方法,符合Swing规范:

class PaintCells extends JPanel {
    private Integer horizontal;
    private Integer vertical;
    private int[][] newOriginalCells;

    public PaintCells(Integer originalHorizontal, Integer originalVertical, int[][] originalCells) {
        this.horizontal = originalHorizontal;
        this.vertical = originalVertical;
        this.newOriginalCells = originalCells;
    }

    // 新增数组更新方法
    public void updateCells(int[][] newCells) {
        this.newOriginalCells = newCells;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < vertical; i++) {
            for (int j = 0; j < horizontal; j++) {
                g.setColor(newOriginalCells[j][i] == 1 ? Color.BLACK : Color.WHITE);
                g.fillRect(j * 25, i * 25, 25, 25);
                g.setColor(newOriginalCells[j][i] == 1 ? Color.WHITE : Color.BLACK);
                g.drawRect(j * 25, i * 25, 25, 25);
            }
        }
    }
}

2. 改用SwingTimer实现世代定时更新

SwingTimer是Swing生态下的标准定时任务工具,回调逻辑运行在EDT中且不会阻塞线程,替代原有的递归+sleep方案:
首先在GameOfLife类中新增Timer成员变量:

class GameOfLife {
    JFrame frame = new JFrame("Game of Life");
    JPanel panel;
    Timer gameTimer; // 新增定时任务变量
    // 其余原有成员变量保持不变

修改newGeneration()方法,删除sleep和递归逻辑,增加数组同步操作:

void newGeneration() {
    newCells = new int[horizontal][vertical];

    for (int l = 0; l < vertical; l++) {
        for (int k = 0; k < horizontal; k++) {
            livingNeighbours = 0;
            // 原有邻居计算逻辑保持不变
            if (k - 1 > -1) {
                if (l - 1 > -1 && cells[k - 1][l - 1] == 1) livingNeighbours++;
                if (l + 1 < vertical && cells[k - 1][l + 1] == 1) livingNeighbours++;
                if (cells[k - 1][l] == 1) livingNeighbours++;
            }
            if (k + 1 < horizontal) {
                if (l - 1 >= 0 && cells[k + 1][l - 1] == 1) livingNeighbours++;
                if (l + 1 < vertical && cells[k + 1][l + 1] == 1) livingNeighbours++;
                if (cells[k + 1][l] == 1) livingNeighbours++;
            }
            if (l - 1 >= 0 && cells[k][l - 1] == 1) livingNeighbours++;
            if (l + 1 < vertical && cells[k][l + 1] == 1) livingNeighbours++;

            if (cells[k][l] == 1) {
                newCells[k][l] = (livingNeighbours == 2 || livingNeighbours == 3) ? 1 : 0;
            } else {
                newCells[k][l] = (livingNeighbours == 3) ? 1 : 0;
            }
        }
    }

    cells = newCells;
    // 同步更新面板的细胞数组
    ((PaintCells)panel).updateCells(cells);
    frame.repaint();
}

修改按键触发逻辑,按下空格时启动定时任务:

frame.addKeyListener(new KeyListener() {
    @Override
    public void keyTyped(KeyEvent e) {
        if (e.getKeyChar() == ' ' && gameTimer == null) {
            // 每1000ms触发一次世代更新
            gameTimer = new Timer(1000, event -> newGeneration());
            gameTimer.start();
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {}

    @Override
    public void keyReleased(KeyEvent e) {}
});

最后不要忘记导入javax.swing.Timer类。

内容的提问来源于stack exchange,提问作者Lovahrk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 13:24:02