Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTreeView sorting questions



  • I'm building a customized file browser with PySide6, and I ran into a number of issues with sorting.

    Here's the part that initializes the model and the tree view:

        self.model = QFileSystemModel()
        self.model.setRootPath(path)
        self.model.setFilter(QDir.NoDot | QDir.AllEntries)
        self.model.sort(0,Qt.SortOrder.AscendingOrder)
        self.ui.treeView.setModel(self.model)
        self.ui.treeView.setRootIndex(self.model.index(path))
        self.ui.treeView.header().setSortIndicator(0, Qt.AscendingOrder)
        self.ui.treeView.setSortingEnabled(True)
    

    Now here are the problems that I'd like to solve.

    1. This line doesn't seem to do anything:
      self.model.sort(0,Qt.SortOrder.AscendingOrder)
      But this one does the actual sorting:
      self.ui.treeView.header().setSortIndicator(0, Qt.AscendingOrder)
      I would like to have the data be sorted by the model and appear sorted in the tree view.
      How do I do that?
      Another issue which seems to be related to this is that when switching between folders the files/folders don't appear on the right places, it takes about half a second for them to be sorted.

    2. I keep two dots .. entry for browsing up the parent folder. I would like to keep two dots always on top, as all the file browsers do. However, if I have a folder with !something subfolder in it, two dots get under it.
      I.e. I would like to have it this way:
      ..
      !something
      folder A
      But it goes like this:
      !something
      ..
      folder A
      I understand that it's because !something is less than .. in terms of standard sorting and I probably have to override it with QSortFilterProxyModel. If I do, what exactly should be done? Or maybe there's a simpler workaround?

    Thanks!


  • Lifetime Qt Champion

    Hi,

    1. The model controls it however the view's initialisation resets it to a known state by the view to ensure that for example you do not have a sorting indicator that says ascending while the content shows descending.
      As for the folder content, QFileSystemModel is asynchronous and does not load the whole content of your filesystem for memory and performance reasons. However several seconds sounds big. Are you folders heavy ?
    2. Do you have the same issue when not sorting at all ?


  • @SGaist Thanks.

    1. So does it mean that it doesn't make sense to set sorting on the model level at all?
      I wrote half a second, not several seconds, but it's still noticeable.
      The interesting fact here is that if I use QFileSystemModel directly it doesn't seem to happen - the folders appear sorted. But when I implement my customization (I'm adding another column with some extra data) there's this slight delay with sorting.
    2. When I comment out all sorting code the folder still appears sorted, but the other way, like so:
      folder A
      ..
      !something

    Basically I would like to keep .. "always on top", is there a way to do this with QFileSystemModel / QTreeView?



  • I submitted a more detailed explanation of my goals and problems here: https://stackoverflow.com/questions/66220009/custom-file-browser-implementation-on-pyside6

    Any advice is appreciated here or on Stack Overflow.



  • Found the solution and posted it to StackOverflow. Pasting it here as well.

    class SortingModel(QSortFilterProxyModel):
        def lessThan(self, source_left: QModelIndex, source_right: QModelIndex):
            file_info1 = self.sourceModel().fileInfo(source_left)
            file_info2 = self.sourceModel().fileInfo(source_right)       
            
            if file_info1.fileName() == "..":
                return self.sortOrder() == Qt.SortOrder.AscendingOrder
    
            if file_info2.fileName() == "..":
                return self.sortOrder() == Qt.SortOrder.DescendingOrder
                    
            if (file_info1.isDir() and file_info2.isDir()) or (file_info1.isFile() and file_info2.isFile()):
                return super().lessThan(source_left, source_right)
    
            return file_info1.isDir() and self.sortOrder() == Qt.SortOrder.AscendingOrder
    

    The code for initializing view and model:

        model = QFileSystemModel()
        model.setRootPath('.')
        model.setFilter(QDir.NoDot | QDir.AllEntries)
        model.sort(0, Qt.SortOrder.AscendingOrder)
        sorting_model = SortingModel()
        sorting_model.setSourceModel(model)
        view.tree_view.setModel(sorting_model)
        view.tree_view.setRootIndex(sorting_model.mapFromSource(model.index('.')))
        view.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)
        view.tree_view.setSortingEnabled(True)
    

Log in to reply