QT 5.10递归过滤系统文件问题:QSortFilterProxyModel子文件不显示
解决QSortFilterProxyModel递归过滤文件时子文件不显示的问题
我刚好踩过这个坑!你的核心问题出在QSortFilterProxyModel的默认行为上:如果父文件夹被过滤掉,它的所有子项都会被自动隐藏;而且如果不对文件夹的过滤逻辑做特殊处理,子文件甚至没机会进入你的过滤判断流程。下面是完整的修复方案:
第一步:自定义代理模型,重写过滤逻辑
你需要继承QSortFilterProxyModel,并重写filterAcceptsRow方法,专门区分文件夹和文件的过滤规则:
#include <QSortFilterProxyModel> #include <QFileSystemModel> class FileFilterProxyModel : public QSortFilterProxyModel { protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override { // 获取源文件系统模型 QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel()); if (!fileModel) return false; // 获取当前行的源索引 QModelIndex sourceIndex = fileModel->index(source_row, 0, source_parent); // 关键:文件夹直接放行 // 只有文件夹能通过过滤,它下面的子文件才会被评估是否显示 if (fileModel->isDir(sourceIndex)) { return true; } // 这里写你的文件过滤规则,示例:只显示txt格式文件 QString fileName = fileModel->fileName(sourceIndex); return fileName.endsWith(".txt", Qt::CaseInsensitive); } };
第二步:在主程序中使用自定义代理模型
替换原来的逻辑,注意要正确转换根索引:
#include <QApplication> #include <QMainWindow> #include <QTreeView> #include <QFileSystemModel> // 上面的FileFilterProxyModel定义放在这里或者单独头文件 int main(int argc, char **argv) { QString path = "C:/"; QApplication app(argc, argv); QMainWindow window; QTreeView* treeView = new QTreeView(&window); // 初始化文件系统模型 QFileSystemModel model; model.setRootPath(path); // 设置显示规则:显示所有条目,隐藏.和.. model.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); // 使用自定义代理模型 FileFilterProxyModel proxyModel; proxyModel.setSourceModel(&model); // 如果需要用字符串过滤,也可以用setFilterFixedString/setFilterRegExp // proxyModel.setFilterFixedString(".txt"); // 给TreeView绑定代理模型 treeView->setModel(&proxyModel); // 关键:将源模型的根索引转换为代理模型的索引 QModelIndex proxyRootIndex = proxyModel.mapFromSource(model.index(path)); treeView->setRootIndex(proxyRootIndex); window.setCentralWidget(treeView); window.resize(800, 600); window.show(); return app.exec(); }
关键要点解释
- 文件夹必须放行:这是子文件能显示的核心!如果文件夹被过滤掉,
QSortFilterProxyModel会直接跳过它的所有子项,根本不会调用filterAcceptsRow去判断子文件。 - 根索引转换:不能直接把
QFileSystemModel的索引传给TreeView,必须用mapFromSource转换成代理模型的索引,否则会出现显示异常。 - 灵活调整过滤规则:如果你的需求不是过滤后缀,而是文件名包含特定字符、文件大小等规则,只需要修改文件判断部分的代码即可。
如果需要同时过滤文件夹,那你要调整文件夹的判断逻辑——比如只有符合条件的文件夹才放行,但要注意:如果父文件夹被过滤,它的所有子项都会被隐藏,这种情况下递归过滤文件夹需要更复杂的逻辑(比如向上遍历父节点判断是否被接受)。
内容的提问来源于stack exchange,提问作者neosettler
相关产品推荐
相关产品推荐

