The following code runs (after importing necessary libraries):
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MainWindow')
self.layout = QHBoxLayout()
self.file_system_widget = FileBrowser()
self.layout.addWidget(self.file_system_widget)
widget = QWidget()
widget.setLayout(self.layout)
self.setCentralWidget(widget)
class FileBrowser(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QVBoxLayout()
self.model = QFileSystemModel()
self.model.setRootPath(self.model.myComputer())
self.model.setNameFilters(['*.*'])
self.model.setNameFilterDisables(1)
self.tree = QTreeView()
self.tree.setModel(self.model)
self.tree.setAnimated(False)
self.tree.setSortingEnabled(True)
layout.addWidget(self.tree)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
try:
os.mkdir('Imports')
except:
pass
main = MainWindow()
main.show()
app.exec()
It gives the following result on my C drive:
(Some of these files are provided here https://drive.google.com/drive/folders/1ejY0CjfEwS6SGS2qe_uRX2JvlruMKvPX).
My objective is to modify the line self.model.setNameFilters(['*.*'])
such that, in the tree view, it only shows files with dcm
extension and also files without extension. That is, the part I draw red gets removed.
How do I achieve such a goal? For keeping dcm
files, I can write lines like self.model.setNameFilters(['*.dcm'])
to keep them and remove the others. But I am not sure how to deal with files without extension or how to deal with the two requirements at the same time .
The QFileSystemModel
class only supports basic wildcard filtering, so you will need to use a QSortFilterProxyModel to get fully customisable filtering. This will allow you to use a regular expression to do the filtering, which achieves most of what you want quite simply. However, reproducing the behaviour of setNameFilterDisables
will require a reimplemention of the flags
method of the proxy model, and the sorting will also need some adjustment.
Below is a simple demo based on your example that implements all of that:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class FilterProxy(QSortFilterProxyModel):
def __init__(self, disables=False, parent=None):
super().__init__(parent)
self._disables = bool(disables)
def filterAcceptsRow(self, row, parent):
index = self.sourceModel().index(row, 0, parent)
if not self._disables:
return self.matchIndex(index)
return index.isValid()
def matchIndex(self, index):
return (self.sourceModel().isDir(index) or
super().filterAcceptsRow(index.row(), index.parent()))
def flags(self, index):
flags = super().flags(index)
if (self._disables and
not self.matchIndex(self.mapToSource(index))):
flags &= ~Qt.ItemIsEnabled
return flags
class FileBrowser(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QVBoxLayout()
self.model = QFileSystemModel()
self.model.setFilter(
QDir.AllDirs | QDir.AllEntries | QDir.NoDotAndDotDot)
self.proxy = FilterProxy(True, self)
self.proxy.setFilterRegularExpression(r'^(.*\.dcm|[^.]+)$')
self.proxy.setSourceModel(self.model)
self.tree = QTreeView()
self.tree.setModel(self.proxy)
self.tree.setAnimated(False)
header = self.tree.header()
header.setSectionsClickable(True)
header.setSortIndicatorShown(True)
header.setSortIndicator(0, Qt.AscendingOrder)
header.sortIndicatorChanged.connect(self.model.sort)
self.model.setRootPath(self.model.myComputer())
root = self.model.index(self.model.rootPath())
self.tree.setRootIndex(self.proxy.mapFromSource(root))
layout.addWidget(self.tree)
self.setLayout(layout)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('MainWindow')
self.layout = QHBoxLayout()
self.file_system_widget = FileBrowser()
self.layout.addWidget(self.file_system_widget)
widget = QWidget()
widget.setLayout(self.layout)
self.setCentralWidget(widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec()