The contents of QFileSystemModel are displayed in a QTreeView, and I want to switch between listing folders only and files only in the current directory. It is first initialized with a filter for folders model.setFilter(QDir.Dirs | QDir.NoDotAndDotDot). Then, when setting the filter for files QDir.Files | QDir.NoDotAndDotDot, the first folder that was displayed before is still shown. I figured it had to do with the first item being the view's currentIndex, so adding view.setCurrentIndex(QModelIndex()) does fix that. However, if a folder is selected and then the filter is switched for displaying files only, that folder will still be shown, even when calling view.clearSelection() right before. (And I would like to keep the selection mode on SingleSelection).
I was wondering if QFileSystemModel was not intended to be used that way, and setFilter should only be used once, or if there is a solution. If I create a new model every time I want to change the filter then it does work properly, but I can't imagine that's the best usage either.
Ultimately, I'll be using a proxy model for other custom filtering. Trying this with a default QSortFilterProxyModel does not update the contents at all when the filter is changed, it only shows the folders. If I include QDir.AllDirs in the filter, as instructed in the docs, it does seem to update the contents correctly. But that option will include folders and files together, when I just want to show files.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Model(QWidget):
def __init__(self):
super().__init__()
model = QFileSystemModel()
model.setFilter(QDir.Dirs | QDir.NoDotAndDotDot | QDir.AllDirs)
model.setRootPath(QDir.rootPath())
self.view = QTreeView(uniformRowHeights=True, itemsExpandable=False, rootIsDecorated=False)
self.view.setModel(model)
self.view.setRootIndex(model.index(QDir.currentPath()))
grid = QGridLayout(self)
grid.addWidget(self.view, 0, 0, 1, 2)
grid.addWidget(QRadioButton('Folders', checked=True), 1, 0, Qt.AlignRight)
grid.addWidget(QRadioButton('Files', toggled=self.changefilter), 1, 1)
def changefilter(self, checked):
self.view.clearSelection()
self.view.setCurrentIndex(QModelIndex())
model = self.view.model()
if checked:
model.setFilter(QDir.Files | QDir.NoDotAndDotDot)# | QDir.AllDirs)
else:
model.setFilter(QDir.Dirs | QDir.NoDotAndDotDot | QDir.AllDirs)
class ModelWithProxy(QWidget):
def __init__(self):
super().__init__()
model = QFileSystemModel()
model.setFilter(QDir.Dirs | QDir.NoDotAndDotDot | QDir.AllDirs)
model.setRootPath(QDir.rootPath())
proxy = QSortFilterProxyModel()
proxy.setSourceModel(model)
self.view = QTreeView(uniformRowHeights=True, itemsExpandable=False, rootIsDecorated=False)
self.view.setModel(proxy)
self.view.setRootIndex(proxy.mapFromSource(model.index(QDir.currentPath())))
grid = QGridLayout(self)
grid.addWidget(self.view, 0, 0, 1, 2)
grid.addWidget(QRadioButton('Folders', checked=True), 1, 0, Qt.AlignRight)
grid.addWidget(QRadioButton('Files', toggled=self.changefilter), 1, 1)
def changefilter(self, checked):
self.view.clearSelection()
self.view.setCurrentIndex(QModelIndex())
proxy = self.view.model()
model = proxy.sourceModel()
if checked:
model.setFilter(QDir.Files | QDir.NoDotAndDotDot)# | QDir.AllDirs)
else:
model.setFilter(QDir.Dirs | QDir.NoDotAndDotDot | QDir.AllDirs)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = QWidget()
hbox = QHBoxLayout(window)
hbox.addWidget(Model())
hbox.addWidget(ModelWithProxy())
window.show()
sys.exit(app.exec_())
I reproduced this behavior with several versions up to PyQt5 5.15 on both Windows and macOS.