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

Java Swing中JTable结合JCheckbox的显示与高亮问题

问题描述

我正在使用JideSoft的SortableTable(因需求限制必须使用该组件),需要实现两个核心功能:

  1. 首列显示Checkbox,用户选中Checkbox时高亮整行
  2. 实时统计选中行的数量

当前遇到的问题:

  • 注释掉StudentSortableTable构造方法中的setDefaultCellRenderer(new CustomRenderer());后,首列Checkbox能正常显示,但无法实现整行高亮
  • 启用自定义渲染器后,首列不再显示Checkbox,仅显示true/false文本,且点击选中时只有首列变色,整行无高亮效果

解决方案

1. 修复Checkbox显示+整行高亮问题

问题根源是默认渲染器覆盖了列级别的Checkbox渲染器。JTable渲染器优先级为:列级渲染器 > 类型级渲染器 > 默认渲染器,因此需要避免默认渲染器覆盖首列的Checkbox渲染器,同时让所有列根据首列选中状态调整背景色。

修改后的StudentSortableTable代码:

public final class StudentSortableTable extends SortableTable {
    private static final long serialVersionUID = 1L;

    private StudentModel studentModel;
    private final List<Student> studentData;
    private final CustomRenderer customRenderer = new CustomRenderer();

    public StudentSortableTable(List<Student> studentData) {
        super();
        this.studentData = studentData;
        updateModel(this.studentData);
        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        // 仅给非首列设置自定义渲染器,避免覆盖首列的Checkbox渲染器
        for (int i = 1; i < getColumnCount(); i++) {
            getColumnModel().getColumn(i).setCellRenderer(customRenderer);
        }
        adjustTable();
    }

    public void updateModel(List<Student> studentData) {
        studentModel = new StudentModel(studentData);
        setModel(studentModel);
        // 更新模型后重新绑定非首列渲染器
        for (int i = 1; i < getColumnCount(); i++) {
            getColumnModel().getColumn(i).setCellRenderer(customRenderer);
        }
        adjustTable();
    }

    public void adjustTable() {
        // 设置首列的Checkbox编辑器和渲染器
        getColumnModel().getColumn(0).setCellEditor(new BooleanCheckBoxCellEditor());
        getColumnModel().getColumn(0).setCellRenderer(new BooleanCheckBoxCellRenderer());
    }

    private class CustomRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                                                       int row, int column) {
            Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            // 根据首列的选中状态设置当前单元格背景,实现整行高亮
            Boolean isRowSelected = (Boolean) studentModel.getValueAt(row, 0);
            if (Boolean.TRUE.equals(isRowSelected)) {
                c.setBackground(Color.orange);
            } else {
                // 保留表格默认选中样式,避免冲突
                c.setBackground(isSelected ? table.getSelectionBackground() : Color.WHITE);
            }
            return c;
        }
    }
}

2. 实现选中行统计功能

通过监听表格模型变化,实时统计选中的行数量,示例如下(添加到JTableDemo中):

void initializeComponent() {
    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());

    studentSortableTable = new StudentSortableTable(getDummyData());
    studentSortableTable.setAutoCreateRowSorter(true);
    panel.add(new JScrollPane(studentSortableTable), BorderLayout.CENTER);

    // 添加统计标签
    JLabel countLabel = new JLabel("选中行数:0");
    panel.add(countLabel, BorderLayout.SOUTH);

    // 监听模型变化,实时更新统计
    studentSortableTable.getModel().addTableModelListener(e -> {
        int count = 0;
        StudentModel model = (StudentModel) studentSortableTable.getModel();
        for (int i = 0; i < model.getRowCount(); i++) {
            if (model.getStudentData(i).isIsSelected()) {
                count++;
            }
        }
        countLabel.setText("选中行数:" + count);
    });

    add(panel);
}

关键补充:同步模型与实体数据

需要在StudentModel中重写setValueAt方法,确保Checkbox的状态变化同步到Student对象:

@Override
public void setValueAt(Object aValue, int row, int column) {
    super.setValueAt(aValue, row, column);
    if (column == 0) {
        Student student = studentData.get(row);
        student.setIsSelected((Boolean) aValue);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:17:35