不调用refresh()方法刷新JavaFX TableView的可行解决方案咨询
关于Extractor Callback方案的适用性
Extractor Callback不是该场景的合适解决方案。
Extractor Callback的核心作用是为ObservableList指定元素内部需要监听的属性,仅当元素自身的属性发生变更时,才会触发列表的更新通知进而驱动TableView刷新。而你的场景中底层数据本身没有任何变化,发生变更的是全局展示规则这类外部状态,Extractor Callback完全无法感知这类外部变更,因此无法实现预期的刷新效果。
更优的实现思路
按优先级从高到低推荐以下两种方案:
方案1:单元格级别绑定全局展示规则
这是性能最优的实现,仅会刷新实际需要变更内容的单元格,无冗余开销:
- 为所有受展示规则影响的列自定义
cellFactory,在创建TableCell时,为单元格绑定全局的展示规则ObservableValue - 规则变更时,仅触发当前单元格重新执行渲染逻辑,不需要操作整个表格
- 注意使用
WeakChangeListener绑定监听器,或者在单元格dispose时主动移除监听器,避免内存泄漏
示例代码逻辑:
// 全局展示规则可观察对象 ObjectProperty<DisplayRule> displayRule = new SimpleObjectProperty<>(DisplayRule.DEFAULT); // 列的cellFactory定义 numberCol.setCellFactory(col -> new TableCell<DataItem, Number>() { private final ChangeListener<DisplayRule> ruleListener = (obs, old, newRule) -> updateItem(getItem(), isEmpty()); { // 绑定规则监听器,使用弱监听避免内存泄漏 displayRule.addListener(new WeakChangeListener<>(ruleListener)); } @Override protected void updateItem(Number value, boolean empty) { super.updateItem(value, empty); if (empty || value == null) { setText(null); return; } // 根据当前规则格式化数值 setText(DisplayUtils.formatByRule(value, displayRule.get())); } });
方案2:单元格值工厂绑定组合规则
如果你的列不需要自定义复杂的单元格渲染,可以直接在cellValueFactory中返回组合了展示规则的绑定对象,规则变更时会自动触发对应单元格的内容更新:
numberCol.setCellValueFactory(cellData -> Bindings.createStringBinding( () -> DisplayUtils.formatByRule(cellData.getValue().getTargetValue(), displayRule.get()), // 绑定两个触发源:数据本身的属性、全局展示规则 cellData.getValue().targetValueProperty(), displayRule ) );
该方案无需自定义单元格,代码更简洁,适合格式化逻辑简单的场景。
为什么不推荐原有的refresh()方案
table.refresh()会强制重绘表格所有可见单元格,哪怕单元格内容不需要变更,数据量较大时会产生明显的性能损耗,同时可能触发不必要的单元格动画、临时丢失输入焦点等副作用。
内容的提问来源于stack exchange,提问作者Jim D
相关产品推荐
相关产品推荐

