Java Swing问题:康威生命游戏JPanel更新世代时无法获取新值
问题排查与修复方案
核心故障原因
- 数组引用未同步
构造PaintCells实例时,你将初始cells数组的引用传递给了PaintCells内部的newOriginalCells变量。后续在newGeneration()中执行cells = newCells时,仅修改了GameOfLife类中cells变量的指向,PaintCells内部存储的数组引用仍然指向旧数组,因此绘制时永远读取的是初始数据,不会更新。 - 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
相关产品推荐
相关产品推荐

