文件更改时QFileSystemModel不更新

时间:2017-12-17 00:20:55

标签: python qt pyqt updates qfilesystemmodel

我遇到QFileSystemModel没有显示文件更改的问题。首次创建文件时,它会立即显示。但是当文件本身发生更改时,大小和时间戳不会更新。我已尝试多次尝试强制模型更新但没有取得真正的成功。我所取得的最好成就是完全取代模型。虽然这会导致此错误:

QSortFilterProxyModel: index from wrong model passed to mapToSource

下面的测试代码创建了一个空目录的表视图。单击左键会创建一个文件(foo.txt)。连续点击会将数据附加到文件中。我的理解是QFileSystemModel不需要刷新,但第二个按钮是我的尝试。

对于我做错的任何帮助都将不胜感激!

# Testing with python3.6.3 and pip installed pyqt5 5.9.2 in virtualenv on Ubuntu
import os, sys, tempfile
from PyQt5 import QtCore, QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)

        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)
        self._view = QtWidgets.QTableView()
        layout.addWidget(self._view)

        self._modify_button = QtWidgets.QPushButton('Create')
        layout.addWidget(self._modify_button)
        self._refresh_button = QtWidgets.QPushButton('Refresh')
        layout.addWidget(self._refresh_button)

        self._modify_button.clicked.connect(self._modify)
        self._refresh_button.clicked.connect(self._refresh)

        self._model, self._proxy = None, None
        self.temp_dir = tempfile.TemporaryDirectory(dir=os.path.dirname(os.path.abspath(__file__)))
        self.init_model(self.temp_dir.name)

    def init_model(self, path):
        self._model = QtWidgets.QFileSystemModel()
        self._model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.AllEntries)

        self._proxy = QtCore.QSortFilterProxyModel(self)
        self._proxy.setSourceModel(self._model)
        self._view.setModel(self._proxy)
        # self._view.setModel(self._model)

        self._model.directoryLoaded.connect(self._loaded)
        self._model.setRootPath(path)

    def _loaded(self):
        path = self._model.rootPath()
        source_index = self._model.index(path)
        index = self._proxy.mapFromSource(source_index)
        self._view.setRootIndex(index)
        # self._view.setRootIndex(source_index)

    def _modify(self):
        """Create or modify foo.txt..model should see and update"""
        self._modify_button.setText('Modify')
        file_name = os.path.join(self.temp_dir.name, 'foo.txt')
        with open(file_name, 'a') as txt_file:
            print('foo', file=txt_file)

    # def _refresh(self):
    #     # This only seems to work once..and its a flawed approach since it requires permission to write
    #     temp = tempfile.NamedTemporaryFile(dir=self.temp_dir.name)

    # def _refresh(self):
    #     self._model.beginResetModel()
    #     self._model.endResetModel()

    # def _refresh(self):
    #     self._proxy.setFilterRegExp('foo')
    #     self._proxy.setFilterRegExp(None)
    #     self._proxy.invalidate()
    #     self._proxy.invalidateFilter()
    #     self._proxy.reset()
    #
    #     root_index = self._model.index(self._model.rootPath())
    #     rows = self._model.rowCount(root_index)
    #     proxy_root_index = self._proxy.mapFromSource(root_index)
    #     topLeft = self._proxy.index(0, 0, proxy_root_index)
    #     bottomRight = self._proxy.index(rows - 1, self._model.columnCount(proxy_root_index) - 1, proxy_root_index)
    #     # self._proxy.dataChanged.emit(topLeft, bottomRight)
    #     self._model.dataChanged.emit(topLeft, bottomRight)

    # def _refresh(self):
    #     # This only seems to work once
    #     self._model.setRootPath('')
    #     self._model.setRootPath(self.temp_dir.name)

    def _refresh(self):
        # This seems heavy handed..but seems to work
        # ..though generates "QSortFilterProxyModel: index from wrong model passed to mapToSource" spam in console
        self.init_model(self.temp_dir.name)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    widget = Widget()
    widget.show()
    sys.exit(app.exec_())

2 个答案:

答案 0 :(得分:3)

&LT p为H.;<强> UPDATE< /强>:其中/ p为H. < p>从Qt-5.9.4起,< code> QT_FILESYSTEMMODEL_WATCH_FILES< / code> envrionment变量可用于打开每个文件的监视(参见< a href =" https://bugreports.qt.io/browse/QTBUG-46684" rel =" nofollow noreferrer&# 34;> QTBUG-46684< / A&GT)。这需要设置< em>一次< / em>在模型开始缓存有关文件的信息之前,为非空值。但请注意,这会将文件监视器添加到< strong>< em>遇到的每个文件< / em>< / strong>,这样就可以使它成为< a href =" https ://doc.qt.io/qt-5/qfilesystemwatcher.html#details" rel =" nofollow noreferrer">某些系统上昂贵的解决方案< / a>。< / p> < p>原始答案留在下面作为问题的解释。< / p> < HR> < p>此问题是由长期存在的Qt错误造成的:< a href =" https://bugreports.qt.io/browse/QTBUG-2276" rel =" nofollow noreferrer"> QTBUG-2276< / a>。不幸的是,目前看来很快就会修复它。如错误报告评论中所示,问题的核心似乎是:< / p> < BLOCKQUOTE>   < p>这是一个操作系统限制。对文件的更改并不意味着目录   已修改。< / p> < / BLOCKQUOTE> < p>唯一真正的解决方法是附加< code> QFileSystemWatcher< / code> < em>每个文件< / em>,显然可以是< a href =" https://doc.qt.io/qt-5/qfilesystemwatcher.html#details" rel =" nofollow noreferrer">非常昂贵< / a> (无论如何,在某些平台上)。< / p> < p>除了这个问题,< a href =" https://doc.qt.io/qt-5/qfilesystemmodel.html" rel =" nofollow noreferrer"> QFileSystemModel< / a> class目前还没有提供强制刷新的API,正如你所发现的那样,似乎没有任何可靠的解决办法。大多数"解决方案"在SO和其他地方提供,建议一些变体:< / p> < pre>< code> root = fsmodel.rootPath() fsmodel.setRootPath('') fsmodel.setRootPath(根) < /代码>< /预> < p>但是如你所知,这似乎只能工作一次 - 可能是由于当前实现了文件信息缓存的方式有些怪癖。< / p> < p>目前看来强制更新的唯一方法是替换< em>整个模型< / em>。您可以通过重构< code> init_model< / code>来阻止您当前执行此操作所产生的错误消息。像这样的方法:< / p> < pre>< code> def init_model(self,path):     如果self._proxy为None:         self._proxy = QtCore.QSortFilterProxyModel(self)     其他:         #删除当前的源模型         self._proxy.setSourceModel(无)     self._model = QtWidgets.QFileSystemModel()     self._model.setFilter(QtCore.QDir.AllDirs | QtCore.QDir.AllEntries)     self._proxy.setSourceModel(self._model)     self._view.setModel(self._proxy)     self._model.directoryLoaded.connect(self._loaded)     self._model.setRootPath(路径) < /代码>< /预> < p>这是一个非常令人不满意的情况,但目前似乎没有任何明显的方法。< / p>

答案 1 :(得分:0)

从Qt v5.9.4开始,您可以设置环境变量QT_FILESYSTEMMODEL_WATCH_FILES,您可以在changelog中了解更多相关信息:

  

[QTBUG-46684]现在可以启用每个文件观看        设置环境变量QT_FILESYSTEMMODEL_WATCH_FILES,        允许跟踪文件大小的变化。

一些事情:

  • 目前您需要将其设置为before initializing the model,之后您可以将其设置为另一个文件夹而不会出现任何问题。
  • 请注意,此功能的代价是潜在的重负荷。