1

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:

enter image description here

(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.

enter image description here

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 .

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
温泽海
  • 216
  • 3
  • 16
  • You can't from QFileSystemModel (see [this related post](https://stackoverflow.com/q/58099772) for the explanation). You need to set a custom QSortFilterProxyModel subclass in order to do that (a basic proxy wouldn't work, as it would apply the filter to both files *and* directories). – musicamante Jun 11 '22 at 21:22
  • @musicamante Thanks for responding! I have looked at the post but I am still stuck on how to proceed. I am especially not sure on the syntax as I am unable to find relevant examples in python. I would really appreciate more hints and examples on how to proceed. – 温泽海 Jun 12 '22 at 18:27

1 Answers1

2

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:

screenshot

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()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336