旧版Qt如何让filterAcceptsRow不过滤含匹配子项的父节点?
旧版Qt树形视图递归过滤实现方案
你需要的核心逻辑是在filterAcceptsRow中增加子节点的递归匹配校验:只要当前节点本身匹配,或是存在任意子节点匹配,就返回True保留当前节点,就可以解决父节点过滤导致子节点无法展示的问题。
基础实现(不关联展开状态,全量递归检查)
直接修改你的过滤代理代码即可:
def filterAcceptsRow(self, source_row, source_parent_index): model = self.sourceModel() source_index = model.index(source_row, 0, source_parent_index) # 检查当前节点本身是否匹配过滤规则 d = model.searchableData(source_index) if self.isVisible(d): return True # 递归检查所有子节点是否存在匹配项,有匹配则保留当前父节点 if model.hasChildren(source_index): child_row_count = model.rowCount(source_index) for child_row in range(child_row_count): if self.filterAcceptsRow(child_row, source_index): return True # 自身不匹配且无匹配子节点,隐藏该节点 return False
结合节点展开状态的实现
如果你需要仅对已展开的节点检查子节点,未展开的节点仅校验自身,需要额外维护已展开节点的索引集合:
- 给过滤代理类添加成员变量存储已展开的源模型索引
- 绑定树形视图的展开/收起信号,实时更新索引集合
- 调整过滤逻辑,仅已展开节点才递归检查子节点
# 视图初始化时绑定信号(proxy为你的过滤代理实例) tree_view.expanded.connect(lambda proxy_idx: proxy.expanded_indexes.add(tree_view.model().mapToSource(proxy_idx)) ) tree_view.collapsed.connect(lambda proxy_idx: proxy.expanded_indexes.discard(tree_view.model().mapToSource(proxy_idx)) ) # 过滤代理中的实现 class YourFilterProxy(QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent) self.expanded_indexes = set() # 存储已展开的源模型索引 def filterAcceptsRow(self, source_row, source_parent_index): model = self.sourceModel() source_index = model.index(source_row, 0, source_parent_index) # 检查当前节点本身是否匹配 d = model.searchableData(source_index) if self.isVisible(d): return True # 仅已展开的节点才检查子节点匹配情况 if model.hasChildren(source_index) and source_index in self.expanded_indexes: child_row_count = model.rowCount(source_index) for child_row in range(child_row_count): if self.filterAcceptsRow(child_row, source_index): return True return False
注意事项
- 如果树的节点数量极多、层级很深,可以给递归结果加缓存提升过滤性能
- 每次修改过滤关键词后需要调用
invalidateFilter()触发全量重过滤 - 该实现完全兼容旧版Qt,效果和新版
setRecursiveFilteringEnabled(true)一致
内容的提问来源于stack exchange,提问作者pawel
相关产品推荐
相关产品推荐

