JTable搭配RowSorter切换过滤器时如何避免应用模型选中值被清空
解决方案:避免JTable过滤/排序时修改应用层Model选中值
核心思路
问题根源是JTable内部执行过滤、排序操作时,会临时清空选中再尝试恢复,这些内部操作会触发你自定义ListSelectionModel的重写方法,进而同步修改应用层Model。我们只需要将JTable内部的临时选中操作和用户主动的选中操作区分开,临时操作只修改视图层选中状态,不同步到应用层Model即可。
具体实现
方案1:通过RowSorter监听控制同步开关(对应你要求的第一类方案)
- 给自定义的
TimeZoneListSelectionModel添加同步开关标记
public final class TimeZoneListSelectionModel extends DefaultListSelectionModel implements ApplicationModelSelectionListener { // 新增:是否忽略UI层的选中变更,不同步到应用Model private boolean ignoreUiSelectionChanges = false; public void setIgnoreUiSelectionChanges(boolean ignore) { this.ignoreUiSelectionChanges = ignore; } // ... 原有代码保持不变 // 修改三个重写的选中操作方法,增加开关判断 @Override public void clearSelection() { if (ignoreUiSelectionChanges) { super.clearSelection(); return; } appMdl.setModelSelection(null); } @Override public void setSelectionInterval(int index0, int index1) { if (ignoreUiSelectionChanges) { super.setSelectionInterval(index0, index1); return; } int modelIdx = tbl.convertRowIndexToModel(index0); String value = appMdl.getData()[modelIdx]; appMdl.setModelSelection(value); } @Override public void addSelectionInterval(int index0, int index1) { if (ignoreUiSelectionChanges) { super.addSelectionInterval(index0, index1); return; } int modelIdx = tbl.convertRowIndexToModel(index0); String value = appMdl.getData()[modelIdx]; appMdl.setModelSelection(value); } }
- 给TableRowSorter添加事件监听器,过滤/排序期间关闭同步
在TableProblem构造方法中,初始化完rowSorter后添加如下代码:
rowSorter.addRowSorterListener(e -> { // 排序/过滤开始,暂停同步到应用Model tzListSelectionModel.setIgnoreUiSelectionChanges(true); // 等待JTable内部的选中恢复逻辑全部执行完成后,再恢复同步 SwingUtilities.invokeLater(() -> { tzListSelectionModel.setIgnoreUiSelectionChanges(false); // 主动同步一次应用Model的选中状态到视图,确保视图状态和Model一致 tzListSelectionModel.modelSelectionChanged( appMdl.getModelSelection(), appMdl.findModelIndex(appMdl.getModelSelection()) ); }); });
方案2:重写JTable的sorterChanged方法(对应你要求的第二类方案)
你也可以通过重写JTable的sorterChanged方法实现开关控制,无需额外监听RowSorter事件:
tbl = new JTable(mdl) { @Override public void sorterChanged(RowSorterEvent e) { tzListSelectionModel.setIgnoreUiSelectionChanges(true); super.sorterChanged(e); SwingUtilities.invokeLater(() -> { tzListSelectionModel.setIgnoreUiSelectionChanges(false); tzListSelectionModel.modelSelectionChanged( appMdl.getModelSelection(), appMdl.findModelIndex(appMdl.getModelSelection()) ); }); } };
实现效果
修改完成后:
- 切换过滤器时,应用层Model的选中值不会被清空,不会触发多余的关联数据加载
- 选中项被过滤掉时,仅视图层清空选中,Model保留原有选中值
- 过滤器切回原范围后,视图会自动恢复选中状态,完全符合预期行为
内容的提问来源于stack exchange,提问作者Pixelstix
相关产品推荐
相关产品推荐

