How to customize QSortFilterProxyModel to display specific folders?
-
i want to make a custom file manager that just shows specific folders.
like this screenshot: only normal folders are displayed in the treeView, and only special folders ending with .asset are diaplayed in the listView.
my current approach is to take two separate QFileSystemModel and put them into two QSortFilterProxyModel, one to remove the .asset folder and one to display only the .asset folder.
but it never works as expected.some interface code:
root_path = "f:/root_folder" # two separate QFileSystemModel treeModel = QFileSystemModel() listModel = QFileSystemModel() # only folders treeModel.setFilter(QDir.NoDotAndDotDot | QDir.Dirs) listModel.setFilter(QDir.NoDotAndDotDot | QDir.Dirs) # i just want the model to search 'f:/root_folder': treeModel.setRootPath(root_path) listModel.setRootPath(root_path) # one custom QSortFilterProxyModel, it determines whether to display specific folders based on the parameters. treeProxy = myProxyModel(False) treeProxy.setSourceModel(treeModel) listProxy = myProxyModel(True) listProxy.setSourceModel(listModel) # view # 'ui' is a QWidget object, contains treeView and listView. ui.treeView.setModel(treeProxy) ui.treeView.setRootIndex(treeProxy.mapFromSource(treeModel.index(root_path))) ui.listView.setModel(listProxy) ui.listView.setRootIndex(listProxy.mapFromSource(listModel.index(root_path))) # signal and slot ui.treeView.clicked.connect(lambda index: ui.listView.setRootIndex( listProxy.mapFromSource( listModel.setRootPath( treeModel.fileInfo( treeProxy.mapToSource(index) ).absoluteFilePath() )) ))
I first tested QSortFilterProxyModel, which returns True anyway, which means not filtering.
# test: DO NOTHING. class myProxyModel(QSortFilterProxyModel): def __init__(self, isAsset=True, parent=None): super(myProxyModel, self).__init__(parent) self._isAsset = isAsset def filterAcceptsRow(self, source_row, source_parent): return True
So far everything has worked, so I've added the ability to filter .asset.
class myProxyModel(QSortFilterProxyModel): def __init__(self, isAsset=True, parent=None): super(myProxyModel, self).__init__(parent) self._isAsset = isAsset # True only show .asset, False not show .asset def filterAcceptsRow(self, source_row, source_parent): # get item name in the directory source_index = self.sourceModel().index(source_row, 0, source_parent) filename = source_index.data(Qt.DisplayRole) # check if the file name has .asset suffix if self._isAsset: if filename.endswith(".asset"): return True else: return False else: if filename.endswith(".asset"): return False else: return True
the result listView is empty. why is that?
another test:
class myProxyModel(QSortFilterProxyModel): def __init__(self, isAsset=True, parent=None): super(myProxyModel, self).__init__(parent) self._isAsset = isAsset def filterAcceptsRow(self, source_row, source_parent): if not source_parent.isValid(): print("error") return False else: return True
because there's no filtering, the treeView and listView are all working fine.
but there were 4 "error" in the console. what are they??
what exactly does filterAcceptsRow() do?? -
@denni-0 I thought filtering would be very simple in qt, but it's actually quite complicated. I wrote the program this way because both the qt manual and people who i asked said: to filtering out items using QSortFilterProxyModel.
I am new, and no knowledge at C++, so I don't quite understand what you mean. do you want me to write a custom QFileSystemModel? if you're familiar with qt, can you explain What exactly does filterAcceptsRow() do? -
@jackkkkk said in How to customize QSortFilterProxyModel to display specific folders?:
QFileSystemModel
Well, I don't get this line:
filename = source_index.data(Qt.DisplayRole)
You are getting the data for the "Qt.DisplayRole" which obviously is going to return nothing. The
QFileSystemModel
provides the following roles: https://doc.qt.io/qt-5/qfilesystemmodel.html#Roles-enum.
So for your case:filename = source_index.data(Qt.FileNameRole)
-
@jackkkkk said in How to customize QSortFilterProxyModel to display specific folders?:
QFileSystemModel
Well, I don't get this line:
filename = source_index.data(Qt.DisplayRole)
You are getting the data for the "Qt.DisplayRole" which obviously is going to return nothing. The
QFileSystemModel
provides the following roles: https://doc.qt.io/qt-5/qfilesystemmodel.html#Roles-enum.
So for your case:filename = source_index.data(Qt.FileNameRole)
-
@jackkkkk said in How to customize QSortFilterProxyModel to display specific folders?:
QFileSystemModel
Well, I don't get this line:
filename = source_index.data(Qt.DisplayRole)
You are getting the data for the "Qt.DisplayRole" which obviously is going to return nothing. The
QFileSystemModel
provides the following roles: https://doc.qt.io/qt-5/qfilesystemmodel.html#Roles-enum.
So for your case:filename = source_index.data(Qt.FileNameRole)
-
@denni-0 I want it to be as simple as possible. but the more i learned, the harder it became for me to achieve this "simple" goal.
there are two ways to filter the folder list, one in the model and the other in the view. neither is as easy as i thought. maybe i should change the way to my question.
-
@daljit97
Qt.DisplayRole result:
DISK NAME (F:)
DISK NAME (C:)
DISK NAME (D:)
DISK NAME (F:)
...QFileSystemModel.FileNameRole result (no disk name):
F:
C:
D:
F:
...the result shows a list of all disks (which is the top level of the file system), indicating QSortFilterProxyModel.filterAcceptsRow() used an invalid index. look at the last test in my code.