Java Swing 自定义组件库分享(十三)

发布时间:2026/7/6 4:33:33

Java Swing 自定义组件库分享(十三) Java Swing 自定义组件库分享十三表格核心 — CusTable一、背景二、类源码三、核心功能说明四、使用示例五、关于 JTableRowBase六、关于分页七、注意事项八、小结一、背景Swing 原生JTable使用起来比较繁琐每次都需要手动创建DefaultTableModel、设置渲染器、处理事件等。而且原生表格不支持直接绑定数据对象需要将对象转换为 Object 数组。CusTable的作用就是封装JTable的常用操作支持泛型数据绑定、右键菜单复制、单元格编辑控制等功能减少重复代码。二、类源码importcn.hutool.core.collection.CollUtil;importlombok.AllArgsConstructor;importlombok.Data;importlombok.EqualsAndHashCode;importlombok.NoArgsConstructor;importlombok.experimental.Accessors;importjavax.swing.*;importjavax.swing.table.DefaultTableCellRenderer;importjavax.swing.table.DefaultTableModel;importjava.awt.*;importjava.awt.datatransfer.StringSelection;importjava.awt.event.MouseAdapter;importjava.awt.event.MouseEvent;importjava.util.ArrayList;importjava.util.List;/** * 自定义表格 * 支持泛型数据绑定、右键菜单复制、单元格编辑控制 * * 使用示例 * CusTableUser table new CusTable(new String[]{ID, 姓名, 年龄}, user - new Object[]{user.getId(), user.getName(), user.getAge()}); * table.loadData(userList); */EqualsAndHashCode(callSupertrue)DataAccessors(chaintrue)NoArgsConstructorAllArgsConstructorpublicclassCusTableTextendsJTable{/** 列名数组 */privateString[]colsnull;/** 行数据转换器将数据对象转换为 Object 数组 */privateJTableRowBaseTrowBasenull;/** 当前表格数据列表 */privateListTdataListnull;/** 右键菜单 */privateJPopupMenupopupMenunull;/** 右键点击位置 */privatePointpopupMenuPointnull;/** 可编辑列索引-1 表示所有列不可编辑 */privateinteditableColumnIndex-1;/** * 加载数据 * param dataList 数据源 */publicvoidloadData(ListTdataList){this.dataListdataList;DefaultTableModelmodelgetTableModel(dataList);setTable(model);this.validate();this.updateUI();}/** * 设置表格模型及样式 * param model 表格模型 */publicvoidsetTable(DefaultTableModelmodel){this.setModel(model);// 内容居中对齐DefaultTableCellRendererrenderernewDefaultTableCellRenderer();renderer.setHorizontalAlignment(SwingConstants.CENTER);this.setDefaultRenderer(Object.class,renderer);// 单选模式this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);// 显示网格线this.setShowHorizontalLines(true);this.setShowVerticalLines(true);// 单元格间距this.setIntercellSpacing(newDimension(2,2));// 创建右键菜单createPopupMenu();}/** * 根据数据列表生成 TableModel * param dataList 数据源 * return DefaultTableModel */publicDefaultTableModelgetTableModel(ListTdataList){DefaultTableModelmodelnewDefaultTableModel(cols,0){OverridepublicbooleanisCellEditable(introw,intcolumn){returneditableColumnIndex0columneditableColumnIndex;}OverridepublicClass?getColumnClass(intcolumn){if(getRowCount()0getValueAt(0,column)instanceofImageIcon){returnImageIcon.class;}returnsuper.getColumnClass(column);}};dataListCollUtil.isEmpty(dataList)?newArrayList():dataList;this.dataListdataList;dataList.forEach(t-model.addRow(rowBase.getRow(t)));returnmodel;}/** * 获取指定行的数据对象 * param rowIndex 行索引 * return 数据对象 */publicTgetData(introwIndex){returndataList.get(rowIndex);}/** * 获取当前选中行的数据对象 * return 数据对象未选中时返回 null */publicTgetSelectedData(){intselectedRowIndexthis.getSelectedRow();if(selectedRowIndex-1){returnnull;}returndataList.get(selectedRowIndex);}/** * 构造函数使用已有 TableModel * param model 表格模型 */publicCusTable(DefaultTableModelmodel){super(model);}/** * 构造函数 * param cols 列名数组 * param rowBase 行数据转换器 */publicCusTable(String[]cols,JTableRowBaseTrowBase){this.colscols;this.rowBaserowBase;loadData(null);}// 右键菜单 /** * 创建右键菜单复制功能 */privatevoidcreatePopupMenu(){popupMenunewJPopupMenu();JMenuItemcopyItemnewJMenuItem(复制);popupMenu.add(copyItem);copyItem.addActionListener(e-copySelectedCell());this.addMouseListener(newMouseAdapter(){OverridepublicvoidmousePressed(MouseEvente){showPopupMenu(e);}OverridepublicvoidmouseReleased(MouseEvente){showPopupMenu(e);}});}/** * 复制选中单元格内容到剪贴板 */privatevoidcopySelectedCell(){if(nullpopupMenuPoint)return;introwthis.rowAtPoint(popupMenuPoint);intcolumnthis.columnAtPoint(popupMenuPoint);if(row0column0){Objectvaluethis.getValueAt(row,column);if(value!null){StringSelectionstringSelectionnewStringSelection(value.toString());Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection,null);}}}/** * 显示右键菜单 * param e 鼠标事件 */privatevoidshowPopupMenu(MouseEvente){if(!e.isPopupTrigger())return;popupMenuPointe.getPoint();introwthis.rowAtPoint(popupMenuPoint);intcolumnthis.columnAtPoint(popupMenuPoint);if(row0column0){popupMenu.show(this,e.getX(),e.getY());}}}三、核心功能说明数据绑定loadData(ListT)加载数据列表自动刷新表格getData(int)根据行索引获取数据对象getSelectedData()获取当前选中行的数据对象列配置cols列名数组定义表格列头editableColumnIndex可编辑列索引-1 表示不可编辑右键菜单右键点击单元格弹出菜单支持复制单元格内容到系统剪贴板样式单元格内容居中对齐显示水平/垂直网格线单选模式四、使用示例4.1 基本用法// 定义列名String[]cols{ID,姓名,年龄,性别};// 定义行数据转换器JTableRowBaseUserrowBaseuser-newObject[]{user.getId(),user.getName(),user.getAge(),user.getGender()};// 创建表格CusTableUsertablenewCusTable(cols,rowBase);// 加载数据table.loadData(userList);// 添加到滚动面板JScrollPanescrollPanenewJScrollPane(table);panel.add(scrollPane);4.2 获取选中数据JButtonbtnnewJButton(查看详情);btn.addActionListener(e-{Userselectedtable.getSelectedData();if(selected!null){System.out.println(选中selected.getName());}else{JOptionPane.showMessageDialog(null,请先选择一行);}});4.3 设置可编辑列table.setEditableColumnIndex(2);// 只允许编辑第3列年龄4.4 刷新表格// 数据变更后重新加载table.loadData(newUserList);4.5 右键复制用户右键点击任意单元格选择复制即可将单元格内容复制到剪贴板。五、关于 JTableRowBaseJTableRowBase是一个函数式接口用于将数据对象转换为表格行数据publicinterfaceJTableRowBaseT{Object[]getRow(Tt);}六、关于分页CusTable本身不包含分页功能。分页属于业务层逻辑可根据项目需求自行实现或使用PageToolBar等分页组件配合使用。七、注意事项泛型CusTableT支持泛型确保数据类型安全数据转换rowBase负责将T转换为Object[]需与cols顺序一致右键复制复制功能默认启用不需要可移除createPopupMenu()调用可编辑列通过editableColumnIndex控制-1 表示全部不可编辑空数据处理传入null或空列表时表格显示空行图片列自动识别ImageIcon类型并正确渲染八、小结CusTable封装了JTable的常用功能简化了表格的使用流程泛型支持避免类型转换数据绑定与刷新一行搞定内置右键复制功能灵活的编辑控制结合后续介绍的渲染器/编辑器可以实现更丰富的表格交互。

相关新闻