Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to customize QSortFilterProxyModel to display specific folders?

How to customize QSortFilterProxyModel to display specific folders?

Scheduled Pinned Locked Moved Unsolved Qt for Python
8 Posts 3 Posters 1.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • JackkkkkJ Offline
    JackkkkkJ Offline
    Jackkkkk
    wrote on last edited by
    #1

    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.
    alt text

    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??

    1 Reply Last reply
    0
    • JackkkkkJ Offline
      JackkkkkJ Offline
      Jackkkkk
      wrote on last edited by
      #2

      @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?

      1 Reply Last reply
      0
      • D Offline
        D Offline
        daljit97
        wrote on last edited by
        #3

        @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)
        
        JackkkkkJ 2 Replies Last reply
        0
        • D daljit97

          @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)
          
          JackkkkkJ Offline
          JackkkkkJ Offline
          Jackkkkk
          wrote on last edited by
          #4

          @daljit97 AttributeError: type object 'PySide2.QtGui.Qt' has no attribute 'FileNameRole'
          i think you might mean QFileSystemModel.FileNameRole, it doesn't work.

          1 Reply Last reply
          0
          • D daljit97

            @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)
            
            JackkkkkJ Offline
            JackkkkkJ Offline
            Jackkkkk
            wrote on last edited by
            #5

            @daljit97 after retesting, QFileSystemModel.FileNameRole and Qt.DisplayRole get similar results. they all get the name of the folders or disk. so that's not the problem.

            1 Reply Last reply
            0
            • JackkkkkJ Offline
              JackkkkkJ Offline
              Jackkkkk
              wrote on last edited by
              #6

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

              1 Reply Last reply
              0
              • D Offline
                D Offline
                daljit97
                wrote on last edited by
                #7

                @Jackkkkk what is the output of print(filename)?

                JackkkkkJ 1 Reply Last reply
                0
                • D daljit97

                  @Jackkkkk what is the output of print(filename)?

                  JackkkkkJ Offline
                  JackkkkkJ Offline
                  Jackkkkk
                  wrote on last edited by
                  #8

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

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved