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

点击按钮生成迷宫后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");
            }
        }
    }     
}

界面截图

界面截图1
界面截图2


核心问题分析

  1. 绘制逻辑放错位置:重写了JFrame的paint方法,但实际要显示迷宫的是maze_box这个JPanel,JFrame的绘制内容会被其子组件覆盖,导致看不到绘制的迷宫。
  2. 监听器实例不统一:给按钮添加的是new View()作为监听器,会创建新的View对象,和main方法里的JFrame不是同一个实例,生成的迷宫数据存在新实例中,界面所在实例根本没有该数据。
  3. paint方法错误:两次调用super.paint(g),第二次调用会覆盖之前绘制的所有内容,等于白画。
  4. 未触发重绘:生成迷宫后没有通知组件重新绘制,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 13:05:23