2017-12-17 18 views
1

QFileSystemModelでファイルの変更が表示されない。ファイルが最初に作成されると、すぐに表示されます。しかし、ファイル自体が変更されると、サイズとタイムスタンプは更新されません。私はモデルが本当に成功することなく更新するように強制しようとする試みを複数試みました。私が達成した最高ののは、モデルを完全に置き換えることです。このエラーの結果:ファイルが変更されたときにQFileSystemModelが更新されない

QSortFilterProxyModel: index from wrong model passed to mapToSource 

以下のテストコードは、空のディレクトリのテーブルビューを作成します。クリックすると左のボタンがファイル(foo.txt)を作成します。連続してクリックすると、ファイルにデータが追加されます。 QFileSystemModelがリフレッシュする必要はないと私は理解していましたが、2番目のボタンはそれを試したものです。

私が間違っていることについての助けがあれば、大歓迎です!

# 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_()) 
+0

あなたのファイルに['QFileSystemWatcher'](http://doc.qt.io/qt-5/qfilesystemwatcher.html)を直接使ってみてください。しかし、多くのファイルを見るとパフォーマンスが低下する可能性があります。 –

答えて

2

この問題は、長年のQtのバグが原因です:QTBUG-2276。残念ながら、現在のところ、すぐに修正される可能性は低いです。バグレポートのコメントで示されているように、問題の核心は、このように思わ:

It's an OS limitation. A change to a file does not mean the directory is modified.

このための唯一の本当の回避策は、明らかにされるであろう、QFileSystemWatcherにすべての単一のファイルを添付することですprohibitively expensive(ほとんどのプラットフォームでは、とにかく)。

QFileSystemModelクラスには現在、リフレッシュを強制するためのAPIが用意されていません。発見したように、そのための信頼できる回避策はないようです。 SO、他の場所で提供されるほとんどの「ソリューション」は、このいくつかの変種示唆:

root = fsmodel.rootPath() 
fsmodel.setRootPath('') 
fsmodel.setRootPath(root) 

をしかし、あなたが知っているように、これは一度だけ動作するようです - おそらくファイル情報のキャッシュが現在実装されている方法で、いくつかの癖に。

現時点では、モデル全体をに置き換えるだけで更新を強制することができます。

def init_model(self, path): 
    if self._proxy is None: 
     self._proxy = QtCore.QSortFilterProxyModel(self) 
    else: 
     # remove the current source model 
     self._proxy.setSourceModel(None) 
    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(path) 

これは非常に不十分な状況ですが、ちょうどでその周りに任意の明白な方法があるようには思えない。これのあなたの現在の実装によって生成されるエラーメッセージは、このようなあなたのinit_model方法をリファクタリングすることによって防止することができます瞬間。

+0

私はモデルを再初期化しようとしていますが、警告、問題へのリンク、および修正について説明してくれてありがとう! –

関連する問題