是否可以创建一个仅在特定列表中显示文件的“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))
注意:类 和常量的名称应始终以大写字母开头。
我正在尝试制作一个显示某个主文件的所有连接文件的应用程序。当您单击主文件时,它会显示所有需要它的文件的列表。当我开始制作应用程序时,我一整天都被困在这里,意识到如何创建一个 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))
注意:类 和常量的名称应始终以大写字母开头。