1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| import sys from PyQt5.QtWidgets import QApplication, QTreeView, QVBoxLayout, QMainWindow, QWidget, QFileSystemModel from PyQt5.QtCore import QDir from PyQt5 import QtWidgets, QtCore
class CheckableFileSystemModel(QtWidgets.QFileSystemModel): checkStateChanged = QtCore.pyqtSignal(str, bool)
def __init__(self): super().__init__() self.checkStates = {} self.rowsInserted.connect(self.checkAdded) self.rowsRemoved.connect(self.checkParent) self.rowsAboutToBeRemoved.connect(self.checkRemoved)
def checkState(self, index): return self.checkStates.get(self.filePath(index), QtCore.Qt.Unchecked)
def setCheckState(self, index, state, emitStateChange=True): path = self.filePath(index) if self.checkStates.get(path) == state: return self.checkStates[path] = state if emitStateChange: self.checkStateChanged.emit(path, bool(state))
def checkAdded(self, parent, first, last): if not parent.isValid(): return if self.filePath(parent) in self.checkStates: state = self.checkState(parent) for row in range(first, last + 1): index = self.index(row, 0, parent) path = self.filePath(index) if path not in self.checkStates: self.checkStates[path] = state self.checkParent(parent)
def checkRemoved(self, parent, first, last): for row in range(first, last + 1): path = self.filePath(self.index(row, 0, parent)) if path in self.checkStates: self.checkStates.pop(path)
def checkParent(self, parent): if not parent.isValid(): return childStates = [self.checkState(self.index(r, 0, parent)) for r in range(self.rowCount(parent))] newState = QtCore.Qt.Checked if all(childStates) else QtCore.Qt.Unchecked oldState = self.checkState(parent) if newState != oldState: self.setCheckState(parent, newState) self.dataChanged.emit(parent, parent) self.checkParent(parent.parent())
def flags(self, index): return super().flags(index) | QtCore.Qt.ItemIsUserCheckable
def data(self, index, role=QtCore.Qt.DisplayRole): if role == QtCore.Qt.CheckStateRole and index.column() == 0: return self.checkState(index) return super().data(index, role)
def setData(self, index, value, role, checkParent=True, emitStateChange=True): if role == QtCore.Qt.CheckStateRole and index.column() == 0: self.setCheckState(index, value, emitStateChange) for row in range(self.rowCount(index)): self.setData(index.child(row, 0), value, QtCore.Qt.CheckStateRole, checkParent=False, emitStateChange=False) self.dataChanged.emit(index, index) if checkParent: self.checkParent(index.parent()) return True
return super().setData(index, value, role)
class TestWindow(QMainWindow): def __init__(self): super().__init__()
model = QFileSystemModel() model.setRootPath(QDir.rootPath())
tree_view = QTreeView() tree_view.setModel(model) tree_view.setRootIndex(model.index(QDir.rootPath())) layout = QVBoxLayout() layout.addWidget(tree_view)
central_widget = QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget)
self.setWindowTitle("File Explorer") self.setGeometry(300, 300, 800, 600)
def main(): app = QApplication(sys.argv) window = TestWindow() window.show() sys.exit(app.exec_())
if __name__ == "__main__": main()
|