QSortFilterProxyModel嵌套冲突致行号错误及性能问题求助
问题分析与解决方案
核心问题总结
- 代理层级映射错误:自定义代理基于搜索代理构建,但行号转换逻辑混乱,导致行号匹配异常,进而引发筛选结果错误、新增行定位偏差。
- 性能瓶颈:
filterAcceptsRow中遍历所有选中项做匹配,50k行下时间复杂度为O(n*m),直接导致7秒级耗时。
分步修复方案
1. 重构自定义代理筛选逻辑,解决映射与性能问题
修改SortFilterProxyModel,改用选中行号集合实现O(1)快速查询,同时修正代理间的行号转换逻辑:
class SortFilterProxyModel(QSortFilterProxyModel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._selected_rows = set() # 存储源模型的选中行号 def setFilterByCheckbox(self, checkstates): # 提取源模型的选中行号,存入集合 self._selected_rows = {idx.row() for idx, is_checked in checkstates if is_checked} self.invalidateFilter() def clearFilter(self): self._selected_rows.clear() self.invalidateFilter() def filterAcceptsRow(self, source_row, source_parent): if not self._selected_rows: return True # 将搜索代理的行号转换为源模型行号 source_proxy_idx = self.sourceModel().index(source_row, 0, source_parent) source_model_idx = self.sourceModel().mapToSource(source_proxy_idx) if not source_model_idx.isValid(): return False # 直接判断行号是否在选中集合中,O(1)查询 return source_model_idx.row() in self._selected_rows
2. 修正主窗口的代理调用逻辑
简化showSelected方法,无需额外处理映射,直接传递源模型的选中状态:
def showSelected(self, state=None): self.custom_proxy_model.clearFilter() if state: self.custom_proxy_model.setFilterByCheckbox(self.model.checks.items())
3. 解决新增行定位错误
新增行后,需按代理层级从源模型行号逐层转换到最上层代理,再执行定位:
假设新增行后获取到源模型行号new_source_row,执行以下代码:
# 源模型 → 搜索代理 proxy_idx = self.proxy_model.mapFromSource(self.model.index(new_source_row, 0)) # 搜索代理 → 自定义代理 custom_proxy_idx = self.custom_proxy_model.mapFromSource(proxy_idx) # 定位目标行 self.tableView.scrollTo(custom_proxy_idx) self.tableView.setCurrentIndex(custom_proxy_idx)
关键优化说明
- 性能飞跃:将遍历匹配改为集合O(1)查询,50k行下筛选耗时可降至毫秒级。
- 映射正确性:严格遵循代理链的
mapToSource/mapFromSource转换规则,确保行号在多层代理间传递无误。 - 逻辑简化:移除冗余的异常捕获和无效判断,让筛选逻辑更清晰可控。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

