PyQt5のQFileSystemWatcherでフォルダを監視するテスト

PyQt5でファイルの監視を試してみる為にQFileSystemWatcherを使ってみました。

ファイルリストの表示

QListViewに監視するフォルダ内のファイルパスを表示することにしました。ファイルパスの表示は、下記のコードのようにフォルダ内のファイルを取得して、全ての行を削除してから行の追加、データの登録という処理を行います。

def updateListView(self, path):
    paths = list( path.glob('*.*') )
    self.model.removeRows( 0, self.model.rowCount() )
    self.model.insertRows( 0, len(paths) )
    for row, p in enumerate(paths):
        self.model.setData( self.model.index(row, 0), str(p) )

監視するフォルダのパスをQLineEditで指定

QLineEditに監視するフォルダのパスを入力することにしました。QLineEditのテキストが変更したときには下記のコードを実行して、監視するフォルダのパスを削除、ファイルリストの更新、監視するフォルダのパスを追加という処理をします。

def lineEditChanged(self, text):
    path = Path(text)
    for d in self.fileSystemWatcher.directories():
        self.fileSystemWatcher.removePath(d)
    if not path.exists():
        return
    self.updateListView(path)
    self.fileSystemWatcher.addPath(text)

フォルダ内のファイルが変更されたときの処理

QFileSystemWatcherのdirectoryChangedにdirectory_changedをconnectして、フォルダ内のファイルが変更されたときにdirectory_changedを実行するようにします。

    self.fileSystemWatcher.directoryChanged.connect(self.directory_changed)

def directory_changed(self, string):
    self.updateListView(Path(string))

動作の様子

ソースコード

import sys
from pathlib import Path
from PyQt5 import QtWidgets, QtCore

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.centralLayout = QtWidgets.QVBoxLayout(self.centralWidget)
        self.centralWidget.setLayout(self.centralLayout)

        self.lineEdit = QtWidgets.QLineEdit(self.centralWidget)
        self.listView = QtWidgets.QListView(self.centralWidget)
        self.centralLayout.addWidget(self.lineEdit)
        self.centralLayout.addWidget(self.listView)

        self.model = Model(self.listView)
        self.listView.setModel(self.model)
        self.listView.setItemDelegate(Delegate())

        self.fileSystemWatcher = QtCore.QFileSystemWatcher(self)

        self.lineEdit.textChanged.connect(self.lineEditChanged)
        self.fileSystemWatcher.directoryChanged.connect(self.directory_changed)

    def updateListView(self, path):
        paths = list( path.glob('*.*') )
        self.model.removeRows( 0, self.model.rowCount() )
        self.model.insertRows( 0, len(paths) )
        for row, p in enumerate(paths):
            self.model.setData( self.model.index(row, 0), str(p) )

    def lineEditChanged(self, text):
        path = Path(text)
        for d in self.fileSystemWatcher.directories():
            self.fileSystemWatcher.removePath(d)
        if not path.exists():
            return
        self.updateListView(path)
        self.fileSystemWatcher.addPath(text)

    def directory_changed(self, string):
        self.updateListView(Path(string))

class Model(QtCore.QAbstractItemModel):
    def __init__(self, parent):
        super(Model, self).__init__(parent)
        self.item = []

    def columnCount(self, parent=QtCore.QModelIndex()):
        return 1

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return QtCore.QVariant()
        if role == QtCore.Qt.EditRole or role == QtCore.Qt.DisplayRole:
            return self.item[index.row()]
        return QtCore.QVariant()

    def flags(self, index):
        if index.isValid():
            return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
        return QtCore.Qt.ItemIsEnabled
        
    def index(self, row, column, parent=QtCore.QModelIndex()):
        return self.createIndex( row, column, self.item[row] )

    def insertRow(self, row, parent=QtCore.QModelIndex()):
        self.insertRows(row, 1, parent)

    def insertRows(self, row, count, parent=QtCore.QModelIndex()):
        self.beginInsertRows(parent, row, row + count - 1)
        self.item[row:row] = [ None for _ in range(count) ]
        self.endInsertRows()

    def parent(self, index):
        return QtCore.QModelIndex()

    def removeRow(self, row, parent=QtCore.QModelIndex()):
        self.removeRows(row, 1, parent)

    def removeRows(self, row, count, parent=QtCore.QModelIndex()):
        self.beginRemoveRows(parent, row, row + count - 1)
        del self.item[row:row+count]
        self.endRemoveRows()

    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self.item)

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            self.item[index.row()] = value
            return True
        return False

class Delegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None, setModelDataEvent=None):
        super(Delegate, self).__init__(parent)
        self.setModelDataEvent = setModelDataEvent
 
    def createEditor(self, parent, option, index):
        return QtWidgets.QLineEdit(parent)
 
    def setEditorData(self, editor, index):
        value = index.model().data(index, QtCore.Qt.EditRole)
        editor.setText(str(value))
 
    def setModelData(self, editor, model, index):
        model.setData(index, editor.text())
        if not self.setModelDataEvent is None:
            self.setModelDataEvent()

def main():
    app = QtWidgets.QApplication(sys.argv)
    mainwindow = MainWindow()
    mainwindow.show()
    app.exec()

if __name__ == '__main__':
    main()

記事の共有

関連記事

コメント

comments powered by Disqus