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

Java Swing调用paintComponent绘制网格时添加自定义组件出现显示异常

问题原因

  1. 组件坐标系统混淆:Swing中每个JComponent的paintComponent方法接收的Graphics上下文,坐标原点是当前组件自身的左上角,而非父容器的左上角。你在RectCell中用父容器的全局坐标创建Rectangle,超出了RectCell自身的可视区域,导致绘制内容错位、丢失。
  2. 集合重复添加元素:RectGridPanel的paintComponent方法每次被调用(窗口移动、缩放、重绘都会触发)都会往rects列表添加400个Rectangle对象,会造成内存泄漏,重绘次数越多列表越臃肿,也可能影响绘制性能。
  3. 布局管理器使用逻辑冲突:你已经给RectGridPanel设置了GridLayout布局,布局管理器会自动计算每个子组件RectCell的位置和尺寸,不需要手动传入全局坐标来定位子组件内的绘制内容。

修复代码

修改后RectCell类

public class RectCell extends Cell
{
    Rectangle shape;
    private static final int CELL_SIZE = 40;
    
    public RectCell(Simulator sim)
    {
        super(sim);
        // 绘制坐标改为相对于组件自身左上角
        shape = new Rectangle(0, 0, CELL_SIZE, CELL_SIZE);
    }
    
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setPaint(Color.BLACK);
        g2.fill(shape);
    }
}

修改后RectGridPanel类

public class RectGridPanel extends GridPanel
{
    List<Rectangle> rects;  
    private static final int GRID_COUNT = 20;
    private static final int CELL_SIZE = 40;
    
    public RectGridPanel(Simulator sim)
    {
        super(sim);
        this.rects = new ArrayList<>(GRID_COUNT * GRID_COUNT);        
        // 初始化阶段生成网格矩形对象,避免重绘时重复添加
        for(int x = 1; x < GRID_COUNT * CELL_SIZE + 1; x += CELL_SIZE)
        {
            for(int y = 2; y < GRID_COUNT * CELL_SIZE + 2; y += CELL_SIZE)
            {
                rects.add(new Rectangle(x, y, CELL_SIZE, CELL_SIZE));
            }
        }
        
        this.setLayout(new GridLayout(GRID_COUNT, GRID_COUNT));
        // GridLayout自动排列子组件,无需传入坐标参数
        for(int i = 0; i < GRID_COUNT * GRID_COUNT; i++)
        {
            Cell newCell = new RectCell(sim);
            this.add(newCell);
        }
    }
    
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setPaint(Color.BLACK);
        // 直接遍历预先生成的网格绘制
        for(Rectangle rect : rects)
        {
            g2.draw(rect);
        }
    }
}

额外优化建议

如果不需要单独对每个单元格做交互监听,也可以放弃嵌套子组件的方案,直接在RectGridPanel的paintComponent方法里统一绘制所有单元格,性能会更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:36:02