Java Swing GUI实现迷宫生成器可视化如何添加单元格访问延迟
问题修复方案
问题根源
- 构造函数直接执行阻塞的
generatePath迷宫生成逻辑,卡住了Swing事件调度线程(EDT),导致窗口无法完成初始化渲染,出现空白 - 声明的Swing Timer没有绑定有效的事件回调逻辑,你传入
this作为回调对象,但GUI类未实现ActionListener接口,Timer触发后没有执行对应动作 drawSolution方法当前是一次性遍历绘制所有路径节点,没有和Timer配合实现逐次绘制- 求解按钮未绑定点击监听器,点击后没有触发对应的求解逻辑
修复步骤
1. 补充必要成员变量
// 需提前导入对应工具类:import java.util.List; import java.util.ArrayList; import java.util.Collections; List<Cell> solutionPath; int currentDrawStep = 0; ActionListener timerListener;
2. 重构构造函数,避免阻塞EDT
public GUI() { // 绑定Timer的回调逻辑,每次触发绘制下一个路径节点 timerListener = e -> { if (currentDrawStep < solutionPath.size() - 1) { currentDrawStep++; repaint(); } else { // 所有节点绘制完成后停止Timer ((Timer)e.getSource()).stop(); } }; timer = new Timer(500, timerListener); // 500ms为每步间隔,可自行调整速度 // 迷宫生成逻辑放到异步执行,避免阻塞窗口初始化 SwingUtilities.invokeLater(() -> { m = new MazeWilson(x, y); m.generatePath(); repaint(); }); }
3. 给求解按钮绑定点击事件,触发逐帧绘制
修改main方法中的按钮初始化逻辑,添加监听器:
public static void main(String[] args) { // Swing组件初始化必须放在事件调度线程执行,避免线程安全问题 SwingUtilities.invokeLater(() -> { JFrame f = new JFrame("Maze"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GUI g = new GUI(); f.add(g); JButton solveMaze = new JButton("Lösen"); solveMaze.setFont(new Font("Arial", Font.PLAIN, 40)); solveMaze.setPreferredSize(new Dimension(30, 30)); solveMaze.setBackground(Color.GREEN); solveMaze.setOpaque(true); // 添加求解按钮点击逻辑 solveMaze.addActionListener(e -> { if (g.m == null) return; // 迷宫未生成完成时不执行 g.solve = true; // 先预处理得到完整的路径列表 Cell endCell = g.m.findPath(); g.solutionPath = new ArrayList<>(); for (Cell c = endCell; c != null; c = c.parent) { g.solutionPath.add(c); } Collections.reverse(g.solutionPath); // 把路径调整为从起点到终点的正序 g.currentDrawStep = 0; g.timer.start(); }); f.add(solveMaze, BorderLayout.SOUTH); f.setExtendedState(JFrame.MAXIMIZED_BOTH); f.getContentPane().setBackground(Color.BLACK); f.setVisible(true); f.toFront(); }); }
4. 修改drawSolution方法,按当前进度绘制
public void drawSolution(Graphics g) { if (solutionPath == null || currentDrawStep < 0) return; g.setColor(Color.CYAN); // 只绘制从起点到当前步数的节点和连线 for (int i = 0; i <= currentDrawStep; i++) { Cell c = solutionPath.get(i); g.fillRect(10 + STROKE_WIDTH/2 + c.x * CELL_SIZE, 10 + STROKE_WIDTH/2 + c.y * CELL_SIZE, CELL_SIZE - STROKE_WIDTH, CELL_SIZE - STROKE_WIDTH); if (i > 0) { Cell prev = solutionPath.get(i-1); // 绘制相邻节点的连接部分 switch (c.y - prev.y) { case 1: g.fillRect(10 + STROKE_WIDTH/2 + prev.x * CELL_SIZE, 10 + STROKE_WIDTH/2 + prev.y * CELL_SIZE, CELL_SIZE - STROKE_WIDTH, CELL_SIZE + CELL_SIZE/4 - STROKE_WIDTH); break; case -1: g.fillRect(10 + STROKE_WIDTH/2 + c.x * CELL_SIZE, 10 + STROKE_WIDTH/2 + c.y * CELL_SIZE, CELL_SIZE - STROKE_WIDTH, CELL_SIZE + CELL_SIZE/4 - STROKE_WIDTH); break; } switch (c.x - prev.x ) { case 1: g.fillRect(10 + STROKE_WIDTH/2 + prev.x * CELL_SIZE, 10 + STROKE_WIDTH/2 + prev.y * CELL_SIZE, CELL_SIZE + CELL_SIZE/4 - STROKE_WIDTH, CELL_SIZE - STROKE_WIDTH); break; case -1: g.fillRect(10 + STROKE_WIDTH/2 + c.x * CELL_SIZE, 10 + STROKE_WIDTH/2 + c.y * CELL_SIZE, CELL_SIZE + CELL_SIZE/4 - STROKE_WIDTH, CELL_SIZE - STROKE_WIDTH); break; } } } }
如果需要可视化迷宫生成的过程,也可以参照同样逻辑,把generatePath的步骤拆分到Timer回调中逐次执行并重绘即可。
内容的提问来源于stack exchange,提问作者Salad King
相关产品推荐
相关产品推荐

