如何在 QFileSystemModel 中更新文件信息



首先,这个问题类似于另一个 QFileSystemModel 在文件更改时不更新,主要区别在于在这种情况下,我不想每次更新我的一个文件时都替换整个模型。

在现实世界的示例中,我的应用程序将打开几个文件,所以我基本上只是想了解如何更新一个特定 QFileSystemModel 项目的信息(大小、修改日期(,下面你有一点 mcve 可以使用,正如您在代码中看到的那样,我已经尝试使用 setData:

import sys
import os
from PyQt5.Qt import *  # noqa

class DirectoryTreeWidget(QTreeView):
    def __init__(self, path=QDir.currentPath(), *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_model(path)
        self.expandsOnDoubleClick = False
        self.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.setAutoScroll(True)
    def init_model(self, path):
        self.extensions = ["*.*"]
        self.path = path
        model = QFileSystemModel(self)
        model.setRootPath(QDir.rootPath())
        model.setReadOnly(False)
        model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.AllEntries)
        self.setModel(model)
        self.set_path(path)
    def set_path(self, path):
        self.path = path
        model = self.model()
        index = model.index(str(self.path))
        if os.path.isfile(path):
            self.setRootIndex(model.index(
                os.path.dirname(str(self.path))))
            self.scrollTo(index)
            self.setCurrentIndex(index)
        else:
            self.setRootIndex(index)

class Foo(QWidget):
    def __init__(self, path):
        super().__init__()
        self.path = path
        self.tree_view = DirectoryTreeWidget(path=".")
        self.tree_view.show()
        bt = QPushButton(f"Update {path}")
        bt.pressed.connect(self.update_file)
        layout = QVBoxLayout()
        layout.addWidget(self.tree_view)
        layout.addWidget(bt)
        self.setLayout(layout)
        # New file will automatically refresh QFileSystemModel
        self.create_file()
    def create_file(self):
        with open(self.path, "w") as f:
            data = "This new file contains xx bytes"
            f.write(data.replace("xx", str(len(data))))
    def update_file(self):
        model = self.tree_view.model()
        # Updating a file won't refresh QFileSystemModel, the question is,
        # how can we update that particular item to be refreshed?
        data = "The file updated is much larger, it contains xx bytes"
        with open(self.path, "w") as f:
            f.write(data.replace("xx", str(len(data))))
        # file_info = self.obj.model.fileInfo(index)
        # file_info.refresh()
        index = model.index(self.path)
        model.setData(index, model.data(index))
        QMessageBox.about(None, "Info", f"{self.path} updated, new size is {len(data)}")

def main():
    app = QApplication(sys.argv)
    foo = Foo("foo.txt")
    foo.setMinimumSize(640, 480)
    foo.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

所以问题是,我怎样才能实现update_file更新该特定文件的信息foo.txt

目标是只更新该文件,而不替换整个模型,如下所示,而且一旦该模型项更新,该项目根本不会在视图中排序/移动,那就太好了。

Qt v5.9.4引入了环境变量QT_FILESYSTEMMODEL_WATCH_FILES以解决QTBUG-46684,您可以在更新日志中阅读更多相关信息:

QTBUG-46684 现在可以通过以下方式启用每个文件的监视 设置环境变量QT_FILESYSTEMMODEL_WATCH_FILES, 允许跟踪例如文件大小的变化。

因此,为了使示例正常工作,您只需将 envar 设置为非空值一次,即:

import sys
import os
from PyQt5.Qt import *  # noqa

class DirectoryTreeWidget(QTreeView):
    def __init__(self, path=QDir.currentPath(), *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_model(path)
        self.expandsOnDoubleClick = False
        self.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.setAutoScroll(True)
    def init_model(self, path):
        os.environ["QT_FILESYSTEMMODEL_WATCH_FILES"] = '1'
        self.extensions = ["*.*"]
        self.path = path
        model = QFileSystemModel(self)
        model.setRootPath(QDir.rootPath())
        model.setReadOnly(False)
        model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.AllEntries)
        self.setModel(model)
        self.set_path(path)
    def set_path(self, path):
        self.path = path
        model = self.model()
        index = model.index(str(self.path))
        if os.path.isfile(path):
            self.setRootIndex(model.index(
                os.path.dirname(str(self.path))))
            self.scrollTo(index)
            self.setCurrentIndex(index)
        else:
            self.setRootIndex(index)

class Foo(QWidget):
    def __init__(self, path):
        super().__init__()
        self.path = path
        self.tree_view = DirectoryTreeWidget(path=".")
        self.tree_view.show()
        bt = QPushButton(f"Update {path}")
        bt.pressed.connect(self.update_file)
        layout = QVBoxLayout()
        layout.addWidget(self.tree_view)
        layout.addWidget(bt)
        self.setLayout(layout)
        self.create_file()
    def create_file(self):
        with open(self.path, "w") as f:
            data = "This new file contains xx bytes"
            f.write(data.replace("xx", str(len(data))))
    def update_file(self):
        model = self.tree_view.model()
        data = "The file updated is much larger, it contains xx bytes"
        with open(self.path, "w") as f:
            f.write(data.replace("xx", str(len(data))))
        index = model.index(self.path)
        model.setData(index, model.data(index))
        QMessageBox.about(None, "Info", f"{self.path} updated, new size is {len(data)}")

def main():
    app = QApplication(sys.argv)
    foo = Foo("foo.txt")
    foo.setMinimumSize(640, 480)
    foo.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

几点评论:

  • 您需要在初始化模型之前设置此 env.var。
  • 但是,此功能是以潜在的重负载为代价的。如果此 env.var 打开,将监视缓存的文件。

最新更新