Java Swing 自定义组件库分享(十四)
Java Swing 自定义组件库分享十四渲染器与编辑器一、背景二、设计说明三、CheckBox 渲染器与编辑器四、禁用背景渲染器五、开关渲染器与编辑器六、总结一、背景CusTable支持了基本的数据展示和交互但 Swing 表格真正的强大之处在于渲染器Renderer和编辑器Editor机制。渲染器控制单元格的显示样式颜色、字体、对齐等编辑器控制单元格的编辑行为双击后弹出什么组件通过自定义渲染器和编辑器可以实现复选框、开关、操作按钮等复杂交互让表格不再只是静态数据展示。二、设计说明本篇涉及的四个核心组件1. CheckBox 渲染器与编辑器CheckboxRenderer将Boolean值显示为复选框只读CheckboxEditor允许用户点击复选框切换Boolean值2. 禁用背景渲染器DisableBgCellRenderer禁用单元格选中时的背景高亮常用于操作列3. 开关渲染器与编辑器SwitchCellRenderer将Boolean值显示为滑动开关只读SwitchCellEditor点击开关切换Boolean值并支持业务回调三、CheckBox 渲染器与编辑器3.1 CheckboxRendererimportjavax.swing.*;importjavax.swing.table.DefaultTableCellRenderer;importjava.awt.*;/** * 复选框渲染器 * 将 Boolean 值渲染为 JCheckBox用于表格中的复选框列 * * 使用示例 * TableColumn col table.getColumnModel().getColumn(0); * col.setCellRenderer(new CheckboxRenderer()); */publicclassCheckboxRendererextendsDefaultTableCellRenderer{privatefinalJCheckBoxcheckBoxnewJCheckBox();publicCheckboxRenderer(){checkBox.setHorizontalAlignment(SwingConstants.CENTER);checkBox.setBorder(BorderFactory.createEmptyBorder(0,10,0,0));}OverridepublicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,booleanisSelected,booleanhasFocus,introw,intcolumn){checkBox.setSelected(Boolean.TRUE.equals(value));returncheckBox;}}3.2 CheckboxEditorimportjavax.swing.*;/** * 复选框编辑器 * 允许在表格中通过点击复选框切换 Boolean 值 * * 使用示例 * TableColumn col table.getColumnModel().getColumn(0); * col.setCellEditor(new CheckboxEditor()); */publicclassCheckboxEditorextendsDefaultCellEditor{publicCheckboxEditor(){super(newJCheckBox());}OverridepublicObjectgetCellEditorValue(){return((JCheckBox)getComponent()).isSelected();}}3.3 使用示例TableColumncoltable.getColumnModel().getColumn(0);col.setCellRenderer(newCheckboxRenderer());col.setCellEditor(newCheckboxEditor());四、禁用背景渲染器4.1 DisableBgCellRendererimportjavax.swing.*;importjavax.swing.table.TableCellRenderer;importjava.awt.*;/** * 禁用选中背景色渲染器 * 包装原始渲染器在指定列被选中时使用未选中时的背景色 * * 使用示例 * TableCellRenderer defaultRenderer table.getDefaultRenderer(Object.class); * TableColumn col table.getColumnModel().getColumn(3); * col.setCellRenderer(new DisableBgCellRenderer(defaultRenderer, 3)); */publicclassDisableBgCellRendererimplementsTableCellRenderer{privatefinalTableCellRendererdefaultRenderer;privatefinalintcolumn;publicDisableBgCellRenderer(TableCellRendererdefaultRenderer,intcolumn){this.defaultRendererdefaultRenderer;this.columncolumn;}OverridepublicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,booleanisSelected,booleanhasFocus,introw,intcolumn){ComponentcdefaultRenderer.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);// 如果该列需要禁用选中背景if(isSelectedcolumnthis.column){c.setBackground(table.getBackground());c.setForeground(table.getForeground());}returnc;}}4.2 使用示例// 禁用第3列操作列的选中高亮TableCellRendererdefaultRenderertable.getDefaultRenderer(Object.class);TableColumncoltable.getColumnModel().getColumn(3);col.setCellRenderer(newDisableBgCellRenderer(defaultRenderer,3));五、开关渲染器与编辑器5.1 SwitchCellRendererimportjavax.swing.*;importjavax.swing.table.TableCellRenderer;importjava.awt.*;/** * 开关渲染器 * 将 Boolean 值渲染为 SwitchComponent * * 使用示例 * TableCellRenderer defaultRenderer table.getDefaultRenderer(Object.class); * TableColumn col table.getColumnModel().getColumn(2); * col.setCellRenderer(new SwitchCellRenderer(defaultRenderer)); */publicclassSwitchCellRendererimplementsTableCellRenderer{// 见第九篇privatefinalSwitchComponentswitchComponentnewSwitchComponent();privatefinalTableCellRendererdefaultRenderer;publicSwitchCellRenderer(TableCellRendererdefaultRenderer){this.defaultRendererdefaultRenderer;}OverridepublicComponentgetTableCellRendererComponent(JTabletable,Objectvalue,booleanisSelected,booleanhasFocus,introw,intcolumn){if(valueinstanceofBoolean){switchComponent.setSwitched((Boolean)value);switchComponent.setEnabled(true);JPanelpanelnewJPanel(newFlowLayout(FlowLayout.CENTER,0,5));panel.setPreferredSize(newDimension(100,50));panel.setBackground(table.getBackground());panel.add(switchComponent);returnpanel;}ComponentcomponentdefaultRenderer.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);component.setBackground(table.getBackground());component.setForeground(table.getForeground());returncomponent;}}5.2 SwitchCellEditorimportjavax.swing.*;importjavax.swing.table.TableCellEditor;importjava.awt.*;importjava.awt.event.MouseAdapter;importjava.awt.event.MouseEvent;importjava.util.EventObject;importjava.util.function.BiFunction;/** * 开关编辑器 * 允许在表格中通过点击滑动开关切换 Boolean 值 * * 使用示例 * TableColumn col table.getColumnModel().getColumn(2); * col.setCellEditor(new SwitchCellEditor(table, (row, newState) - { * System.out.println(第 row 行状态变为 newState); * return true; * })); */publicclassSwitchCellEditorextendsAbstractCellEditorimplementsTableCellEditor{// 见第九篇privatefinalSwitchComponentswitchComponentnewSwitchComponent();privateinteditingRow;privatebooleaneditingfalse;//见上一篇privatefinalCusTable?cusTable;privatefinalBiFunctionInteger,Boolean,BooleanswitchAction;publicTSwitchCellEditor(CusTableTcusTable,BiFunctionInteger,Boolean,BooleanswitchAction){this.cusTablecusTable;this.switchActionswitchAction;switchComponent.addMouseListener(newMouseAdapter(){OverridepublicvoidmouseClicked(MouseEvente){if(switchComponent.isEnabled()editing){toggleSwitchState();e.consume();}}});}privatevoidtoggleSwitchState(){booleannewState!switchComponent.isSwitched();// CallbackProcessor见第二篇BooleanresultCallbackProcessor.apply(switchAction,editingRow,newState,false);if(result!nullresult){switchComponent.setSwitched(newState);stopCellEditing();if(null!cusTable){cusTable.repaint();}}else{cancelCellEditing();}}OverridepublicObjectgetCellEditorValue(){returnswitchComponent.isSwitched();}OverridepublicComponentgetTableCellEditorComponent(JTabletable,Objectvalue,booleanisSelected,introw,intcolumn){this.editingRowrow;this.editingtrue;if(valueinstanceofBoolean){switchComponent.setSwitched((Boolean)value);switchComponent.setEnabled(true);JPanelpanelnewJPanel(newFlowLayout(FlowLayout.CENTER,0,5));panel.setPreferredSize(newDimension(100,50));panel.setBackground(table.getBackground());panel.add(switchComponent);SwingUtilities.invokeLater(()-{if(editing){toggleSwitchState();}});returnpanel;}returnswitchComponent;}OverridepublicbooleanisCellEditable(EventObjecte){returneinstanceofMouseEvent;}OverridepublicbooleanshouldSelectCell(EventObjectanEvent){returntrue;}OverridepublicbooleanstopCellEditing(){this.editingfalse;returnsuper.stopCellEditing();}OverridepublicvoidcancelCellEditing(){this.editingfalse;super.cancelCellEditing();}}5.3 使用示例// 设置开关列第2列TableCellRendererdefaultRenderertable.getDefaultRenderer(Object.class);TableColumncoltable.getColumnModel().getColumn(2);col.setCellRenderer(newSwitchCellRenderer(defaultRenderer));col.setCellEditor(newSwitchCellEditor(table,(row,newState)-{// 执行业务逻辑System.out.println(第row行状态变为newState);// 返回 true 表示更新成功界面同步切换returntrue;}));六、总结自定义渲染器和编辑器是 Swing 表格实现复杂交互的核心机制。本篇展示了四种常见的表格交互模式复选框适合布尔值的展示和编辑禁用背景适合操作列等不需要选中高亮的场景滑动开关适合状态切换场景交互更直观