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

Java Swing JList自定义JPanel渲染器内容重复显示问题咨询

问题根本原因

JList的自定义渲染器采用单实例复用机制:整个JList只会创建1个你定义的渲染器实例,所有行渲染时都会复用这同一个实例的getListCellRendererComponent方法。你在方法内每次调用都新增控件、不清除上一行添加的控件,调用多少次就累加多少个控件,自然会出现所有行的元素叠加、重复显示的问题。同时你每次渲染都重复读取图片、创建新控件,也会造成严重的性能浪费。

可行解决方案

渲染器的控件应该在构造方法中一次性创建完成并设置好布局,getListCellRendererComponent方法内只更新控件的内容,不要新增/删除控件。

修改后的CountryRenderer代码(带显示国家名的按钮)

import java.awt.*;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;

public class CountryRenderer extends JPanel implements ListCellRenderer<Country> {
    // 提前声明所有控件
    private final JButton iconBtn;
    private final JTextField nameTxt;

    public CountryRenderer() {
        // 提前设置布局
        setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
        // 提前创建控件
        iconBtn = new JButton();
        iconBtn.setPreferredSize(new Dimension(80,25));
        nameTxt = new JTextField();
        nameTxt.setPreferredSize(new Dimension(80,25));
        // 提前添加到面板,只加一次
        add(iconBtn);
        add(nameTxt);
    }

    @Override
    public Component getListCellRendererComponent(JList<? extends Country> list, Country country, int index,
                                                  boolean isSelected, boolean cellHasFocus) {
        // 仅更新控件内容,不新增控件
        String code = country.getCode();
        Image scaledImg = null;
        try {
            Image rawImg = ImageIO.read(getClass().getResource("./images/" + code + "1.png"));
            scaledImg = rawImg.getScaledInstance(25, 25, Image.SCALE_SMOOTH);
        } catch (IOException e) {
            e.printStackTrace();
        }
        iconBtn.setIcon(scaledImg != null ? new ImageIcon(scaledImg) : null);
        // 更新按钮显示国家名
        iconBtn.setText(country.getName());
        nameTxt.setText(country.getName());

        // 设置选中状态样式
        if (isSelected) {
            setBackground(list.getSelectionBackground());
            setForeground(list.getSelectionForeground());
        } else {
            setBackground(list.getBackground());
            setForeground(list.getForeground());
        }
        return this;
    }
}

注意事项

如果需要实现按钮的点击交互,因为渲染器只是绘制控件的快照,本身不响应事件,需要额外给JList添加MouseListener,通过点击坐标判断点击的行和按钮区域,再处理对应逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:54:04