点击按钮生成迷宫后JPanel未显示更新问题求助
迷宫生成后无法显示的问题解决
问题描述
我想实现点击按钮输入尺寸后,让JPanel显示生成的迷宫。目前已经能获取尺寸并生成迷宫,也确认actionPerformed()能访问到迷宫数据,但点击按钮后只能确认迷宫已创建,却无法显示。我写了paint方法遍历迷宫数组绘制矩形,但不清楚这个方法的调用时机,也不知道怎么手动调用。刚接触GUI开发,求指导。
原代码
public class View extends JFrame implements ActionListener{ private static JPanel maze_box; private static JLabel message; private static JButton generate_button; private static JTextField maze_size; private static JTextField start_stop; private static JButton solve_button; private String coords; private String size; private final ArrayList<Integer> path = new ArrayList<Integer>(); private int[][] maze = {{}}; public void paint(Graphics g){ super.paint(g); g.translate(50,50); int scale = maze_box.getWidth()/maze.length; for(int row=0; row<maze.length; row++){ for(int col=0; col<maze[0].length; col++){ System.out.println("drawing"); Color color; switch (maze[row][col]) { case 1 : color = Color.BLACK; break; case 9 : color = Color.RED; break; default : color = Color.WHITE; }; g.setColor(color); g.fillRect(10*col, 10*row, 10, 10); g.setColor(Color.BLACK); g.drawRect(10*col, 10*row, 10, 10); } } for(int p=0; p<path.size(); p+=2){ System.out.println("drawing"); int pathX = path.get(p); int pathY = path.get(p+1); g.setColor(Color.GREEN); g.fillRect(pathX*10, pathY*10, 10,10); } super.paint(g); } public static void main(String[] args){ JPanel panel = new JPanel(); JFrame frame = new JFrame(); frame.setSize(800,800); frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE); frame.add(panel); frame.setVisible(true); panel.setLayout(null); maze_box = new JPanel(); maze_box.setBounds(100, 20, 600, 400); maze_box.setBackground(Color.GRAY); panel.add(maze_box); message = new JLabel(); message.setBounds(200, 400, 200, 30); panel.add(message); maze_size = new JTextField("size"); maze_size.setBounds(200, 550, 100, 30); panel.add(maze_size); generate_button = new JButton("Generate Maze"); generate_button.setBounds(500, 550, 100, 30); panel.add(generate_button); generate_button.addActionListener( new View()); start_stop = new JTextField("coords"); start_stop.setBounds(200, 600, 100, 30); panel.add(start_stop); solve_button = new JButton("Solve!"); solve_button.setBounds(500, 600, 100, 30); panel.add(solve_button); solve_button.addActionListener(new View()); } @Override public void actionPerformed( ActionEvent aActionEvent ) { if ( aActionEvent.getSource() == generate_button ){ this.size = maze_size.getText(); try{ int sized = Integer.parseInt(this.size); if(sized>199){ message.setText("Please choose a smaller width"); }if(sized<=0 || this.size.equals("")){ message.setText("Please enter valid numbers"); }else{ System.out.println("generating: "); this.maze = new Generate(sized,sized).maze; System.out.println("done "+ this.maze[0][2]); } }catch(NumberFormatException e){ message.setText("Please enter valid numbers"); } } } }
界面截图


核心问题分析
- 绘制逻辑放错位置:重写了
JFrame的paint方法,但实际要显示迷宫的是maze_box这个JPanel,JFrame的绘制内容会被其子组件覆盖,导致看不到绘制的迷宫。 - 监听器实例不统一:给按钮添加的是
new View()作为监听器,会创建新的View对象,和main方法里的JFrame不是同一个实例,生成的迷宫数据存在新实例中,界面所在实例根本没有该数据。 - paint方法错误:两次调用
super.paint(g),第二次调用会覆盖之前绘制的所有内容,等于白画。 - 未触发重绘:生成迷宫后没有通知组件重新绘制,Swing不会自动感知数据变化,需要手动触发。
修正步骤和代码示例
1. 自定义迷宫绘制面板
创建专门负责绘制迷宫的JPanel子类,用paintComponent(Swing组件推荐的绘制方法)实现绘制逻辑:
class MazePanel extends JPanel { private int[][] maze = {{}}; private final ArrayList<Integer> path = new ArrayList<>(); @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 先绘制组件背景 g.translate(50, 50); int cellSize = 10; // 可根据面板大小动态调整,此处先固定 for (int row = 0; row < maze.length; row++) { for (int col = 0; col < maze[0].length; col++) { Color color; switch (maze[row][col]) { case 1: color = Color.BLACK; break; case 9: color = Color.RED; break; default: color = Color.WHITE; } g.setColor(color); g.fillRect(col * cellSize, row * cellSize, cellSize, cellSize); g.setColor(Color.BLACK); g.drawRect(col * cellSize, row * cellSize, cellSize, cellSize); } } // 绘制路径 for (int p = 0; p < path.size(); p += 2) { int pathX = path.get(p); int pathY = path.get(p + 1); g.setColor(Color.GREEN); g.fillRect(pathX * cellSize, pathY * cellSize, cellSize, cellSize); } } // 设置迷宫数据并触发重绘 public void setMaze(int[][] newMaze) { this.maze = newMaze; repaint(); // 通知组件重新绘制 } // 设置路径数据并触发重绘 public void setPath(ArrayList<Integer> newPath) { this.path.clear(); this.path.addAll(newPath); repaint(); } }
2. 修改View类,统一实例并修正逻辑
将静态组件改为成员变量,用当前View实例作为监听器,生成迷宫后更新MazePanel的数据:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; public class View extends JFrame implements ActionListener { private MazePanel mazeBox; private JLabel message; private JButton generateButton; private JTextField mazeSize; private JTextField startStop; private JButton solveButton; private String coords; private String size; private final ArrayList<Integer> path = new ArrayList<>(); public View() { initUI(); } private void initUI() { setSize(800, 800); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panel = new JPanel(); panel.setLayout(null); add(panel); mazeBox = new MazePanel(); mazeBox.setBounds(100, 20, 600, 400); mazeBox.setBackground(Color.GRAY); panel.add(mazeBox); message = new JLabel(); message.setBounds(200, 400, 200, 30); panel.add(message); mazeSize = new JTextField("size"); mazeSize.setBounds(200, 550, 100, 30); panel.add(mazeSize); generateButton = new JButton("Generate Maze"); generateButton.setBounds(500, 550, 100, 30); panel.add(generateButton); generateButton.addActionListener(this); startStop = new JTextField("coords"); startStop.setBounds(200, 600, 100, 30); panel.add(startStop); solveButton = new JButton("Solve!"); solveButton.setBounds(500, 600, 100, 30); panel.add(solveButton); solveButton.addActionListener(this); } @Override public void actionPerformed(ActionEvent aActionEvent) { if (aActionEvent.getSource() == generateButton) { size = mazeSize.getText(); try { int sized = Integer.parseInt(size); if (sized > 199) { message.setText("请选择更小的尺寸"); } else if (sized <= 0 || size.isEmpty()) { message.setText("请输入有效的数字"); } else { System.out.println("generating: "); int[][] newMaze = new Generate(sized, sized).maze; mazeBox.setMaze(newMaze); System.out.println("done " + newMaze[0][2]); } } catch (NumberFormatException e) { message.setText("请输入有效的数字"); } } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { new View().setVisible(true); }); } }
关键改动说明
- 自定义MazePanel:将绘制逻辑封装在专门面板中,符合Swing组件设计规范,
paintComponent保证组件背景正确绘制。 - 统一监听器实例:用当前View对象作为按钮监听器,确保生成的迷宫数据能直接传递给界面上的MazePanel。
- 触发重绘:调用
repaint()是手动触发Swing组件绘制的标准方式,Swing会自动在合适时机调用paintComponent。 - EDT线程创建界面:用
SwingUtilities.invokeLater在事件调度线程中创建界面,避免线程安全问题,符合Swing开发规范。
内容的提问来源于stack exchange,提问作者beatmaister
相关产品推荐
相关产品推荐

