如何使用QFileSystemModel的索引来跟踪项目的子集?

时间:2017-12-03 20:40:51

标签: python qt pyqt

我正在尝试创建一个文件选择器对话框,该对话框使用复选框来允许选择多个文件。另外,我想对话以开始已经选择的一些项目。我在网上找到了一些使用QTreeViewQFileSystemModel的子类来做这个的例子。在完全呈现对话框后,如何将我最初检查的文件路径列表与描述这些路径的模型中的QModelIndex项连接起来?

我查看的示例保留了应该检查哪些QModelIndex项的列表,并覆盖QFileSystemModel子类的某些方法,如data()方法,以便在检查项目时更新此列表或未选中。为了支持在首次创建对话框时检查某些项目,我尝试使用应预先检查的第二个文件路径列表。在我的data()子类的QFileSystemModel方法中,我检查QModelIndex输入的文件路径,如果它在我预先检查的列表中,我从中移除文件路径预检列表并将QModelIndex放入其他已检查项目列表中。我遇到的问题是模型似乎在创建过程中会多次重新生成。第一次为具有特定路径的索引调用data(),该路径从预检查列表中删除,QModelIndex添加到另一个列表。但是,一旦完全显示对话框,该文件路径的QModelIndex与放入预检查列表的实例不同,因此我的代码不知道应该检查它。 / p>

这是一个说明我的意思的例子:

import os
import sys

from PyQt5 import QtWidgets

all_entries = list()


class MyFileSystemModel(QtWidgets.QFileSystemModel):

    def data(self, index, role):
        if index not in all_entries:
            all_entries.append(index)
        return super().data(index, role)


class Ui_Dialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self, parent)

        self.model = MyFileSystemModel()
        self.model.setRootPath(os.path.abspath('.'))

        self.tree = QtWidgets.QTreeView()
        self.tree.setModel(self.model)
        self.tree.setRootIndex(self.model.index(os.path.abspath('.')))

        self.llayout = QtWidgets.QVBoxLayout(parent)
        self.but = QtWidgets.QPushButton("OK")

        self.llayout.addWidget(self.tree)
        self.llayout.addWidget(self.but)

        self.setLayout(self.llayout)

        self.but.clicked.connect(self.print_entries)

    def print_entries(self):
        print('*'*80)
        for index in all_entries:
            print(index, os.path.relpath(self.model.filePath(index),
                                         os.path.abspath('.')))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    ui = Ui_Dialog()
    ui.show()

    sys.exit(app.exec_())

在包含名为test的单个文件的目录中运行此脚本,然后单击OK按钮,我看到

********************************************************************************
<PyQt5.QtCore.QModelIndex object at 0x7ff46b991f28> test
<PyQt5.QtCore.QModelIndex object at 0x7ff46b991f98> test
<PyQt5.QtCore.QModelIndex object at 0x7ff46b910048> test
<PyQt5.QtCore.QModelIndex object at 0x7ff46b9100b8> test

因此,all_entries最终会为QModelIndex文件路径提供四个不同的test项。在我更复杂的可检查对话框中,我最终会在QModelIndex处的0x7ff46b991f28实例中查看已检查项目列表,但似乎一旦显示对话框,我需要在{{1}使用实例}}。我可以处理我自己的路径列表中的所有内容而不使用0x7ff46b9100b8个对象,但使用它们的优点是QModelIndex使用文件系统观察程序来跟踪文件系统更改,我想利用它来跟踪所选文件的属性,而无需查询文件系统以判断文件是否已更改。

1 个答案:

答案 0 :(得分:1)

问题有以下原因:

  • QModelIndex不应用于区分模型的项目,根据docs
  

注意:应立即使用模型索引然后丢弃。您   调用模型后,不应依赖索引保持有效   更改模型结构或删除项目的函数。如果   你需要随着时间的推移保持模型索引使用QPersistentModelIndex。

  • 文件在QFileSystemModel中有多个关联列,保存第一列的索引是合适的。

enter image description here

考虑到这两点,代码应该如下:

all_entries = list()


class MyFileSystemModel(QtWidgets.QFileSystemModel):
    def data(self, index, role):
        if index.column() == 0:
            if QPersistentModelIndex(index) not in all_entries:
                all_entries.append(QPersistentModelIndex(index))
        return super().data(index, role)

[...]

def print_entries(self):
    print('*'*80)
    for index in all_entries:
        ix = QModelIndex(index) # get QModelIndex from QPersistentModelIndex
        print(index, os.path.relpath(self.model.filePath(ix),os.path.abspath('.')))