如何创建仅展示指定文件列表的QFileSystemModel并修正筛选逻辑反向问题?
解决QFileSystemModel筛选指定文件列表及反向筛选问题
首先,咱们先解决你当前遇到的点击左侧文件后右侧同名文件消失的问题——这完全是因为你的filterAcceptsRow逻辑写反了!你现在的代码是当文件名匹配时返回False(把匹配的文件过滤掉),而我们需要的是匹配时返回True(只保留匹配的文件)。
第一步:修正反向筛选逻辑
修改你的modifiedQSortFilterProxyModel中的filterAcceptsRow方法,把判断条件反转:
def filterAcceptsRow(self, source_row, source_parent): filename = self.sourceModel().index(source_row, 0, source_parent).data() # 现在只保留和目标文件名匹配的文件 if filename == self.file: return True else: return False
这样修改后,当你点击左侧的文件时,右侧TreeView就只会显示同名的文件了,完全符合你的预期。
第二步:扩展支持显示指定文件列表
如果你需要展示的是一个固定文件列表(比如你提到的main_file1 = ["[053ALO] - test file.txt", ...]),我们可以进一步扩展proxy model,让它支持接收一个允许显示的文件列表,而不是单个文件名:
class modifiedQSortFilterProxyModel(QSortFilterProxyModel): def __init__(self): super().__init__() self.file = '' # 添加属性存储允许显示的文件列表 self.allowed_files = [] def filterAcceptsRow(self, source_row, source_parent): filename = self.sourceModel().index(source_row, 0, source_parent).data() # 优先使用文件列表筛选,如果列表不为空,则只保留列表中的文件 if self.allowed_files: return filename in self.allowed_files # 如果列表为空,再使用单个文件名匹配逻辑 elif self.file: return filename == self.file # 默认显示所有文件 else: return True
之后你可以直接设置这个列表来展示指定文件:
# 示例:设置要显示的文件列表 self.filter_proxy_model.allowed_files = ["[053ALO] - test file.txt", "[053ALO] - test file.txt", "[053ALO] - test file.txt"] self.filter_proxy_model.invalidateFilter()
完整修正后的代码
把这些修改整合到你的代码中,最终版本如下:
import sys from PyQt5.QtWidgets import QApplication, QWidget, QTreeView, QFileSystemModel, QHBoxLayout from PyQt5.QtCore import QSortFilterProxyModel, Qt class modifiedQSortFilterProxyModel(QSortFilterProxyModel): def __init__(self): super().__init__() self.file = '' self.allowed_files = [] def filterAcceptsRow(self, source_row, source_parent): filename = self.sourceModel().index(source_row, 0, source_parent).data() if self.allowed_files: return filename in self.allowed_files elif self.file: return filename == self.file else: return True class FileSystemView(QWidget): def __init__(self): super().__init__() appWidth = 800 appHeight = 300 self.setWindowTitle('File System Viewer') self.setGeometry(300, 300, appWidth, appHeight) dir_path = r'<Your directory>' # 替换成你的目标目录 # -- left -- # self.model = QFileSystemModel() self.model.setRootPath(dir_path) self.tree = QTreeView() self.tree.setModel(self.model) self.tree.setRootIndex(self.model.index(dir_path)) self.tree.setColumnWidth(0, 250) self.tree.setAlternatingRowColors(True) self.tree.clicked.connect(self.onClicked) # -- right -- # self.model2 = QFileSystemModel() self.model2.setRootPath(dir_path) self.filter_proxy_model = modifiedQSortFilterProxyModel() self.filter_proxy_model.setSourceModel(self.model2) self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.filter_proxy_model.setDynamicSortFilter(True) self.filter_proxy_model.setFilterKeyColumn(0) root_index = self.model2.index(dir_path) proxy_index = self.filter_proxy_model.mapFromSource(root_index) self.tree2 = QTreeView() self.tree2.setModel(self.filter_proxy_model) self.tree2.setRootIndex(proxy_index) self.tree2.setColumnWidth(0, 250) self.tree2.setAlternatingRowColors(True) # 可选:初始化时显示指定文件列表 # self.filter_proxy_model.allowed_files = ["[053ALO] - test file.txt", "[053ALO] - test file.txt", "[053ALO] - test file.txt"] # self.filter_proxy_model.invalidateFilter() # -- layout -- # layout = QHBoxLayout() layout.addWidget(self.tree) layout.addWidget(self.tree2) self.setLayout(layout) def onClicked(self, index): path = self.sender().model().fileName(index) # 点击时清空文件列表,切换为单个文件名匹配模式 self.filter_proxy_model.allowed_files = [] self.filter_proxy_model.file = path self.filter_proxy_model.invalidateFilter() if __name__ == '__main__': app = QApplication(sys.argv) demo = FileSystemView() demo.show() sys.exit(app.exec_())
关键说明
- 使用
QSortFilterProxyModel是正确的做法:QFileSystemModel本身不支持自定义筛选,通过代理模型包装它,既能保留原模型提供的文件图标、大小/修改时间等详细信息,又能实现自定义筛选逻辑。 invalidateFilter():每次修改筛选条件后必须调用这个方法,触发代理模型重新计算筛选结果,否则界面不会更新。- 优先级逻辑:我们设置了文件列表优先于单个文件名的筛选规则,你可以根据场景灵活切换——比如初始化时显示指定列表,点击左侧文件后切换到显示同名文件。
内容的提问来源于stack exchange,提问作者Eliazar
相关产品推荐
相关产品推荐

