Reputation: 2110
I am trying to create a file browser which will group sequential files in the same director together in a tree view. For example if you had the following files in a directory: img.001.png
img.002.png
img.003.png
, images 2 & 3 would appear as children of image 1 in a QTreeView. They would simply be made children of the first sequential item in the directory.
I have tried a number of ways to accomplish this but so far performance has been a huge issue. Doing it all manually with a QStandardItemModel and python os module was very slow and cumbersome. The QFileSystemModel is surprisingly fast and includes a ton of convenient functions for renaming files, etc, so I am trying to work with that as my base. I tried creating a QStandardItemModel as a sort of "proxy model" which iterated over the QFileSystemModel when the root dir changed. This allowed me to create all of the functionality I need, but was shockingly slow (I guess there is a lot of signaling under the hood or something?). Setting a root dir in the FileSystemModel takes virtually no time, but with a custom model iterating over rows and re-interpreting data it can take 5-10 seconds for one folder with 1000+ files.
So I am thinking that the best solution would be to subclass the QFileSystemModel directly because it has methods built in I want and is lightning fast. However I do not know very much about models and I'm not quite sure where to start. I see that there are quite a few signals that can notify me when rows are going to be inserted, have been inserted, are being moved, etc, etc. But at what point would I be able to check if a row was a sequential file, and if so "re-direct" it to be a child of another index?
Hopefully that is all clear, here is a snippet to get up and running. I do not usually post such general questions on SO but I have put a lot of time into this problem and need some direction as to where to go. I don't need you to write my code for me, but rather pointing me in the right direction would be very helpful!
import sys, os, re
from PyQt5 import QtWidgets
class TestApp(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.tree = QtWidgets.QTreeView(self)
self.model = QtWidgets.QFileSystemModel()
self.proxyModel = ProxyModel(self.model)
self.tree.setModel(self.proxyModel)
self.model.setRootPath("test/dir/with/lots/of/files")
self.model.directoryLoaded.connect(self.update)
def update(self):
self.proxyModel.update_model_from_source()
class ProxyModel(QtGui.QStandardItemModel):
def __init__(self, sourceModel):
super().__init__()
self.sourceModel = sourceModel
def update_model_from_source(self):
self.removeRows(0, self.rowCount())
self.sourceModel.sort(0, QtCore.Qt.AscendingOrder)
candidates = {}
parent = self.sourceModel.index(self.sourceModel.rootPath())
for row in range(self.sourceModel.rowCount(parent)):
index = self.sourceModel.index(row, 0, parent)
filename = self.sourceModel.fileName(index)
file_item = QtGui.QStandardItem(filename)
file_item.setIcon(self.sourceModel.fileIcon(index))
filetype = QtGui.QStandardItem(self.sourceModel.type(index))
date = QtGui.QStandardItem(self.sourceModel.lastModified(index).toString("yyyy-MM-dd h:mm.ss")))
size = QtGui.QStandardItem(str(self.sourceModel.size(indes)))
# check for sequences
sequence = False
if not self.sourceModel.isDir(index):
search_str = os.path.splitext(filename)[0]
matches = re.search(r'([0-9]+)$', search_str)
if matches:
candidate = filename[0:matches.start(0)]
if candidate in candidates:
parent_item = candidates[candidate]
sequence = True
else:
candidates[candidate] = file_item
row = [file_item, filetype, date, size]
if sequence:
parent_item.appendRow(row)
else:
self.appendRow(row)
if __name__ == "__main__":
app = QtWidgets.QApplication()
ex = TestApp()
ex.show()
sys.exit(app.exec_())
Upvotes: 0
Views: 401