# TableCell 实现规则与模式指南 ## 1. 目的与作用 TableCell 是 JavaFX TableView 组件中的关键元素,负责表格中单个单元格的渲染和交互。在 Contract-Manager 项目中,TableCell 主要用于: - 显示各种类型的数据(数字、日期、实体引用等) - 提供自定义的显示格式和样式 - 支持异步加载关联数据 - 实现单元格内编辑功能 ## 2. 文件结构与命名规范 - **文件位置**:`client/src/main/java/com/ecep/contract/controller/table/cell/` - **命名规范**:使用 PascalCase(驼峰命名法,首字母大写),以 `TableCell` 结尾 - 示例:`CompanyTableCell.java`、`LocalDateFieldTableCell.java` ## 3. TableCell 分类与实现模式 ### 3.1 基础 TableCell 直接继承 JavaFX 的 `TableCell` 类,适用于简单的数据显示。 **实现规则**: - 继承 `TableCell`,其中 S 是表格行数据类型,T 是单元格数据类型 - 实现 `updateItem(T item, boolean empty)` 方法 - 提供静态的 `forTableColumn()` 工厂方法 **示例**: ```java public class NumberTableCell extends TableCell { private final NumberStringConverter numberStringConverter; public NumberTableCell(NumberStringConverter numberStringConverter) { this.numberStringConverter = numberStringConverter; } @Override protected void updateItem(Number item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setText(null); } else { setText(numberStringConverter.toString(item)); } } public static Callback, TableCell> forTableColumn(NumberStringConverter numberStringConverter) { return param -> new NumberTableCell<>(numberStringConverter); } } ``` ### 3.2 异步更新 TableCell 继承 `AsyncUpdateTableCell`,用于异步加载并显示关联的实体数据。 **实现规则**: - 继承 `AsyncUpdateTableCell`,其中 V 是表格行数据类型,K 是 ID 类型,T 是实体类型 - 提供构造函数接收服务对象,或实现 `getServiceBean()` 方法从 Spring 容器获取服务 - 可选:重写 `initialize()` 方法自定义实体加载逻辑 - 可选:重写 `format()` 方法自定义实体显示格式 **示例**: ```java @NoArgsConstructor public class CompanyTableCell extends AsyncUpdateTableCell { public CompanyTableCell(CompanyService companyService) { setService(companyService); } @Override protected CompanyService getServiceBean() { return SpringApp.getBean(CompanyService.class); } } ``` ### 3.3 可编辑 TableCell 实现单元格内编辑功能,如日期选择、文本编辑等。 **实现规则**: - 继承 `TableCell` 或其子类 - 实现 `startEdit()`、`cancelEdit()` 方法 - 在 `updateItem()` 方法中处理编辑状态的显示 - 提供编辑控件和事件处理 **示例**: ```java public class LocalDateFieldTableCell extends TableCell { private final DatePicker datePicker; // 构造函数、converter 属性等 @Override public void startEdit() { if (isEmpty()) { return; } super.startEdit(); setGraphic(datePicker); datePicker.setConverter(getConverter()); datePicker.setValue(getItem()); datePicker.requestFocus(); } @Override public void cancelEdit() { super.cancelEdit(); LocalDate item = getItem(); if (item == null) { setText(null); } else { setText(getConverter().toString(item)); } setGraphic(null); } @Override protected void updateItem(LocalDate item, boolean empty) { // 实现更新逻辑 } } ``` ## 4. AsyncUpdateTableCell 核心功能 `AsyncUpdateTableCell` 是项目中最常用的基类,提供以下核心功能: ### 4.1 异步加载机制 - 显示占位符(`#id`)直到数据加载完成 - 使用线程池执行异步任务 - 自动取消不再需要的异步任务 - 确保在 JavaFX 应用线程更新 UI ### 4.2 实体显示格式化 - 默认使用 `toString()` 方法格式化实体 - 对 `NamedEntity` 和 `BasedEntity` 有特殊处理 - 允许子类重写 `format()` 方法自定义格式 ### 4.3 服务获取方式 - 通过构造函数注入服务 - 或通过 `getServiceBean()` 方法从 Spring 容器获取 ## 5. 特殊情况处理 ### 5.1 非 Integer 类型 ID 当实体 ID 不是 Integer 类型时,需要重写 `initialize()` 方法: ```java @Override protected ContractFileTypeLocalVo initialize() { ContractFileType item = getItem(); ContractFileTypeLocalVo localVo = getServiceBean().findByType( Desktop.instance.getActiveEmployee().localeProperty().get(), item); return localVo; } ``` ### 5.2 自定义显示格式 当需要自定义实体的显示格式时,重写 `format()` 方法: ```java @Override public String format(ContractFileTypeLocalVo entity) { if (entity == null) { return null; } return entity.getValue(); } ``` ## 6. 工厂方法模式 所有 TableCell 类都应提供静态的 `forTableColumn()` 工厂方法,用于创建单元格工厂回调: - 无参数版本:`public static Callback, TableCell> forTableColumn()` - 带服务参数版本:`public static Callback, TableCell> forTableColumn(ServiceType service)` ## 7. 代码规范 - 使用 Lombok 注解(如 `@NoArgsConstructor`)简化代码 - 添加适当的 JavaDoc 注释 - 遵循 JavaFX 最佳实践 - 处理空值和异常情况 - 确保线程安全,UI 更新在 JavaFX 应用线程执行 ## 8. 实现检查清单 创建新的 TableCell 时,请检查以下项目: - [ ] 类名符合 `*TableCell` 命名规范 - [ ] 放置在正确的包路径下 - [ ] 选择合适的基类(TableCell、AsyncUpdateTableCell) - [ ] 实现必要的构造函数 - [ ] 实现或重写 `updateItem()` 方法 - [ ] 提供静态的 `forTableColumn()` 工厂方法 - [ ] 对于异步更新类型,实现 `getServiceBean()` 或提供服务注入 - [ ] 添加适当的注释 - [ ] 处理空值和异常情况 ## 9. 示例实现 ### 9.1 简单数据类型 TableCell 参考 `NumberTableCell.java`、`LocalDateFieldTableCell.java` ### 9.2 实体引用 TableCell 参考 `CompanyTableCell.java`、`ContractTableCell.java` ### 9.3 特殊处理 TableCell 参考 `ContractFileTypeTableCell.java`