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

paintComponent函数反复执行及boxLabels溢出问题求助

问题排查与修复方案

兄弟,我一眼就看穿你代码里的核心问题了——你把组件创建、添加以及集合修改的逻辑放到了paintComponent方法里,这可是Swing开发的大忌,直接导致了你遇到的两个麻烦:

为什么paintComponent会反复执行?

Swing的paintComponent是专门负责组件绘制的方法,系统会在很多场景下自动触发它:窗口大小变化、鼠标悬停/点击、组件刷新等等。而你在这个方法里执行了this.add(boxLabels.get(i))——往容器里添加组件的操作会触发组件层次结构变更,系统会立刻再次调用paintComponent更新界面,这就形成了无限重绘循环,每次点击标签都会让这个循环变本加厉。

为什么boxLabels列表会持续膨胀?

你每次执行paintComponent时,都会执行boxLabels.add(new JLabel("Contents.."))和boxInfo.add(...),相当于每次重绘都往集合里塞新的标签和信息,完全没有清空或复用逻辑,久而久之集合自然会越来越大,内存占用也会飙升。

具体修复步骤

1. 把组件初始化逻辑移出paintComponent

paintComponent只该负责绘制图形,组件的创建、添加应该放到构造函数或者专门的初始化方法里:

  • 在类的成员变量里提前初始化boxLabels和boxInfo集合
  • 当packedBoxes数据更新时,先清空旧内容再重新创建标签,而不是每次重绘都新建

2. 修正packedBoxes的空判断逻辑

你原来的if (packedBoxes != null || packedBoxes.size() != 0)有bug:如果packedBoxes是null,packedBoxes.size()会直接抛出NullPointerException,应该改成&&:

if (packedBoxes != null && !packedBoxes.isEmpty())

3. 分离绘制逻辑与组件管理

  • 绘制箱子和物品的逻辑留在paintComponent里
  • 标签的创建、位置更新、tooltip设置,放到单独的方法中,仅在packedBoxes数据变化时调用,而不是每次重绘都执行

修复后的代码示例

// 类成员变量
private List<JLabel> boxLabels = new ArrayList<>();
private List<String> boxInfo = new ArrayList<>();

// 初始化或数据更新时调用的方法
public void updateBoxLabels() {
    // 先清空旧的标签和信息
    for (JLabel label : boxLabels) {
        this.remove(label);
    }
    boxLabels.clear();
    boxInfo.clear();

    if (packedBoxes == null || packedBoxes.isEmpty()) {
        return;
    }

    int drawboxWidth = (getWidth() / packedBoxes.size()) - (100 / packedBoxes.size()) - 5;
    int drawboxHeight = (getHeight() / 2);
    
    for (int i = 0; i < packedBoxes.size(); i++) {
        JLabel label = new JLabel("Contents..");
        int x = 50 + (drawboxWidth * i) + (i * 5);
        int y = drawboxHeight + 100;
        label.setBounds(x, y, drawboxWidth, 20);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        
        // 生成tooltip信息
        String tooltip = "<html><font face=\"sansserif\"><h2>Box nr."+(i+1)+"</h2>" + 
                         "Percentage filled: "+(int)(((float)packedBoxes.get(i).getUsedSize()/(float) boxHeight)*100)+ "% </html>";
        label.setToolTipText(tooltip);
        
        boxLabels.add(label);
        this.add(label);
    }
    // 触发重绘更新箱子图形
    repaint();
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    setBackground(Color.LIGHT_GRAY);
    g.setColor(Color.BLACK);

    if (packedBoxes != null && !packedBoxes.isEmpty()) {
        int drawboxWidth = (getWidth() / packedBoxes.size()) - (100 / packedBoxes.size()) - 5;
        int drawboxHeight = (getHeight() / 2);

        // 绘制每个箱子里的物品和箱子边框
        for (int i = 0; i < packedBoxes.size(); i++) {
            int x = 50 + (drawboxWidth * i) + (i * 5);
            int currentY = 50;

            // 绘制物品
            for (Item item : packedBoxes.get(i).getItems()) {
                float productHeight = (float) item.height / (float) boxHeight;
                float drawProductHeight = drawboxHeight * productHeight;
                g.setColor(item.color);
                g.fillRect(x, currentY, drawboxWidth, (int) drawProductHeight);
                currentY += drawProductHeight;
            }

            // 绘制箱子边框
            g.setColor(Color.BLACK);
            g.drawRect(x, 50, drawboxWidth, drawboxHeight);
        }
    }
}

额外注意事项

  • 当你的packedBoxes数据更新后,记得调用updateBoxLabels()方法来更新标签,而不是直接触发重绘
  • 尽量避免在paintComponent里执行任何耗时操作或状态修改,保持它只专注于绘制图形
  • 可以考虑使用布局管理器(比如GridLayout或FlowLayout)来管理标签的位置,而不是手动调用setBounds,这样界面适配会更灵活

内容的提问来源于stack exchange,提问作者Remy Van Lis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:16:24