是否可以创建一个仅在特定列表中显示文件的“QFileSystemModel()”?

Is it possible to create a `QFileSystemModel()` that only shows the file in a certain list?

我正在尝试制作一个显示某个主文件的所有连接文件的应用程序。当您单击主文件时,它会显示所有需要它的文件的列表。当我开始制作应用程序时,我一整天都被困在这里,意识到如何创建一个 QFileSystemModel() 只显示特定列表中的文件,因为邮件文件中的所有连接文件都存储在一个列表中.

这是一个例子,我只想显示列表中的文件是:

main_file1 = ["[053ALO] - test file.txt", "[053ALO] - test file.txt", "[053ALO] - test file.txt"]

正如我在其他相关问题上看到的那样,他们提到了 QAbstractItemView 的使用,但我不知道如何使用。我正在考虑迭代列表并在每个项目中制作 QAbstractItemView 并将其附加到树视图,但它不显示图片中显示的每个文件的图标和详细信息。

我的问题:是否可以创建一个只显示特定列表中的文件的QFileSystemModel()

我的测试代码:(我的计划是用左边的主文件,右边的连接文件)

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTreeView, QFileSystemModel, \
    QHBoxLayout

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>'

        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.model2 = QFileSystemModel()
        self.model2.setRootPath(dir_path)
        self.tree2 =  QTreeView()
        self.tree2.setModel(self.model2)
        self.tree2.setRootIndex(self.model2.index(dir_path))
        self.tree2.setColumnWidth(0, 250)
        self.tree2.setAlternatingRowColors(True)

        layout = QHBoxLayout()
        layout.addWidget(self.tree)
        layout.addWidget(self.tree2)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = FileSystemView()
    demo.show()
    sys.exit(app.exec_())

更新:

在@musicamante 的帮助下,我意识到我需要对 QSortFilterProxyModel 进行子类化,以便自定义我想要进行的过滤。我很确定我在下面代码中的方法现在已经结束,但我仍然遇到这个问题,当我单击左侧的文件时,右侧的类似文件消失了。 (看到这个video link

这与我想要发生的事情完全相反。我想要发生的是当我点击左侧的文件时,只有同名的文件才会出现在右侧。

我尝试更改 filterAcceptsRow 中 if else 语句中的条件,但它只是让右侧完全空白。

我在下面提供了测试代码

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 = ''

    def filterAcceptsRow(self, source_row, source_parent):

        filename = self.sourceModel().index(source_row, 0, source_parent).data()
        
        if filename == self.file:
            return False
        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''

        # -- 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)

        # -- 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.file = path
        self.filter_proxy_model.invalidateFilter()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = FileSystemView()
    demo.show()
    sys.exit(app.exec_())

有两个问题。

首先,如果你只想显示与所选文件匹配的索引,你应该return True,而不是False(函数说明如果该行是已接受,表示已显示)。

那么,你不能只根据文件名来过滤:模型是分层的,过滤器也必须匹配父索引(父目录);您看到空白视图的原因是 returning False 来自不匹配的文件名,您正在过滤 out 父目录。
考虑到这一点,如果父级不同,过滤器必须始终接受一个索引,并且最终 return 比较的结果。为此,您可以使用 QFileInfo that refers to the source index, which is returned by the models' fileInfo():

class ModifiedQSortFilterProxyModel(QSortFilterProxyModel):
    fileInfo = None
    def filterAcceptsRow(self, source_row, source_parent):
        if not self.fileInfo:
            return True
        source_index = self.sourceModel().index(source_row, 0, source_parent)
        info = self.sourceModel().fileInfo(source_index)
        if self.fileInfo.absolutePath() != info.absolutePath():
            return True
        return self.fileInfo.fileName() == info.fileName()

    def setFilter(self, info):
        self.fileInfo = info
        self.invalidateFilter()


class FileSystemView(QWidget):
    # ...
    def onClicked(self, index):
        self.filter_proxy_model.setFilter(self.model.fileInfo(index))

注意:类 和常量的名称应始终以大写字母开头。