使用QSortFilterProxyModel过滤时如何保留树形结构?
解决QSortFilterProxyModel过滤树形结构丢失层级的问题
我太懂这个坑了!用QSortFilterProxyModel过滤树形数据时,默认逻辑只会保留直接匹配的项,完全不管父节点的存在,这就是你只看到孤立Item 2的原因。另外你说获取父项返回null,大概率是没正确转换源模型索引导致的,我一步步给你解决:
核心问题分析
默认的filterAcceptsRows只检查当前行是否匹配过滤规则,但树形结构需要的是:只要当前项匹配,或者它的任意子节点(包括深层子节点)匹配,就应该保留当前项(父节点也要保留)。而且你之前获取父项返回null,是因为在代理模型的filterAcceptsRows方法里,直接用了代理模型的parent参数,得先转成源模型的索引才能正确拿到父节点。
解决方案代码实现
重写filterAcceptsRows时,改成递归检查当前项和所有子项的匹配情况,同时正确转换源模型索引:
bool CustomSortFilterProxyModel::filterAcceptsRows(int source_row, const QModelIndex &source_parent) const { // 先拿到源模型中当前行的有效索引 QModelIndex source_index = sourceModel()->index(source_row, filterKeyColumn(), source_parent); if (!source_index.isValid()) { return false; } // 检查当前项本身是否匹配过滤规则 bool isMatch = sourceModel()->data(source_index).toString().contains(filterRegExp()); // 如果当前项不匹配,递归遍历所有子项,只要有一个子项匹配就保留当前父项 if (!isMatch) { int childCount = sourceModel()->rowCount(source_index); for (int i = 0; i < childCount; ++i) { if (filterAcceptsRows(i, source_index)) { isMatch = true; break; } } } // 返回最终匹配结果 return isMatch; }
关键细节说明
- 索引转换:必须用
sourceModel()->index(...)获取源模型的索引,而不是直接用代理模型的索引,这样才能正确遍历树形结构的父节点和子节点,解决你之前父项返回null的问题。 - 递归检查:通过递归遍历子节点,确保只要有一个后代节点匹配,所有祖先节点都会被保留,完美还原你期望的树形层级。
- 性能提示:如果你的树形结构特别深或者节点数量极大,递归可能会有轻微性能损耗,这时可以考虑给匹配结果加个缓存(比如用
QHash存储已检查过的索引状态),但绝大多数场景下直接递归就够用了。
用这个逻辑替换你原来的filterAcceptsRows实现,再用setFilterRegExp过滤含“2”的项,就能得到你想要的带完整层级的结果啦!
内容的提问来源于stack exchange,提问作者user2999980
相关产品推荐
相关产品推荐

