Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] How to make visible / select first item using a (sub)string and QSortFilterProxyModel ?
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] How to make visible / select first item using a (sub)string and QSortFilterProxyModel ?

Scheduled Pinned Locked Moved General and Desktop
13 Posts 3 Posters 7.1k Views 1 Watching
  • 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.
  • M Offline
    M Offline
    mvidelgauz
    wrote on last edited by
    #3

    Thank you jazzycamel for you prompt and detailed answer. And sorry for my late respond ((

    I will try to implement what you suggested (although I need first to translate it to PyQt ))) )

    1 Reply Last reply
    0
    • jazzycamelJ Offline
      jazzycamelJ Offline
      jazzycamel
      wrote on last edited by
      #4

      I actually prototyped this in python first as follows:

      @
      import sip
      sip.setapi('QString', 2)
      sip.setapi('QVariant', 2)

      from PyQt4.QtCore import *
      from PyQt4.QtGui import *

      class Model(QAbstractTableModel):
      def rowCount(self , parent=QModelIndex()): return 100
      def columnCount(self, parent=QModelIndex()): return 1
      def data(self, index, role=Qt.DisplayRole):
      if not (index.isValid() and role==Qt.DisplayRole): return None
      return "{0}".format(index.row())

      class Proxy(QSortFilterProxyModel): pass
      class List(QListView):
      @pyqtSlot(str)
      def search(self, text):
      self.selectionModel().clear()
      if text=="": return

          start=self.model().index(0,0)
          indexes=self.model().match(start, Qt.DisplayRole, text, hits=-1)
      
          for index in indexes:
              self.selectionModel().select(index, QItemSelectionModel.Select)
      

      if name=="main":
      from sys import argv, exit

      class Widget(QWidget):
          def __init__(self, parent=None):
              QWidget.__init__(self, parent)
      
              l=QVBoxLayout(self)
      
              self._search=QLineEdit(self, placeholderText="Search...")
              l.addWidget(self._search)
      
              self._model=Model(self)
              self._proxy=Proxy(self)
              self._proxy.setSourceModel(self._model)
              self._list=List(self)
              self._list.setModel(self._proxy)
              self._search.textChanged.connect(self._list.search)
      
              l.addWidget(self._list)
      
              self.setFocus()
      
      a=QApplication(argv)
      w=Widget()
      w.show()
      w.raise_()
      exit(a.exec_())
      

      @

      Might save you a bit of time and effort. Hope this helps ;o)

      For the avoidance of doubt:

      1. All my code samples (C++ or Python) are tested before posting
      2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
      1 Reply Last reply
      0
      • M Offline
        M Offline
        mvidelgauz
        wrote on last edited by
        #5

        Thank you again jazzycamel for your code snippets!

        First of all, in response to your first reply I want to say that that I used proxy model for the purpose it is designed - I want my ListView to be sorted. And that also helped me to filter items of course. My original code was:
        @
        def lineEditTextEdited(self, text):
        self.listModel.setFilterFixedString(text)
        @

        'self.listModel' in my widget is QSortFilterProxyModel, I'm saving it in setModel() method of widget:
        @
        def setModel(self, model):
        self.listModel = model
        self.listView.setModel(model)
        @

        Now I am trying to use your suggestion. If I understand your code correctly in line 44 you are setting your list's model to proxy model, so in lines 22 and 23 you are calling methods index and match of proxy model. So my first version after change was:

        @
        def lineEditTextEdited(self, text):
        #self.listModel.setFilterFixedString(text)
        self.listView.selectionModel().clear()
        if text=="": return
        start=self.listModel.index(0,0)
        indexes=self.listModel.match(start, QtCore.Qt.DisplayRole, text, hits=-1)
        for index in indexes:
        self.listView.selectionModel().select(index, QItemSelectionModel.Select)
        @

        It didn't work and since I understood from your first reply that I should use original model, not proxy the second version is:

        @
        def lineEditTextEdited(self, text):
        #self.listModel.setFilterFixedString(text)
        self.listView.selectionModel().clear()
        if text=="": return
        start=self.listModel.sourceModel().index(0,0)
        indexes=self.listModel.sourceModel().match(start, QtCore.Qt.DisplayRole, text, hits=-1)
        for index in indexes:
        self.listView.selectionModel().select(index, QItemSelectionModel.Select)
        @

        In both versions 'indexes' result is empty array (0 items)...

        Can you please tell me what is wrong in my code?

        1 Reply Last reply
        0
        • jazzycamelJ Offline
          jazzycamelJ Offline
          jazzycamel
          wrote on last edited by
          #6

          In line 22-23 of my example I am calling the model() method on my view which will return the model to which that view is attached, in this case its the proxy model so your first attempt was correct.

          I'm afraid I can't tell you why this isn't working for your particular application without seeing a bit more code. What type does the data() method of your model return for the DisplayRole? I'm wondering if match is failing because its comparing search type string to something else (QVariant for example).

          Sorry I can't be more help.

          For the avoidance of doubt:

          1. All my code samples (C++ or Python) are tested before posting
          2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
          1 Reply Last reply
          0
          • M Offline
            M Offline
            mvidelgauz
            wrote on last edited by
            #7

            I think the problem is mathflags. If I am typing string from the beginning then everything is working as expected (I see that default value of 'flags' parameter of match method is Qt::MatchFlags( Qt::MatchStartsWith | Qt::MatchWrap )

            But I trying to match by substring - like setFilterFixedString(text) did. So I tried:

            @
            start=self.listModel.sourceModel().index(0,0)
            flags = Qt.MatchFlags(Qt.MatchFixedString)
            indexes=self.listModel.sourceModel().match(start, QtCore.Qt.DisplayRole, text, -1, flags)
            @

            and since you confirmed that I don't need source model:
            @
            start=self.listModel.index(0,0)
            flags = Qt.MatchFlags(Qt.MatchFixedString)
            indexes=self.listModel.match(start, QtCore.Qt.DisplayRole, text, -1, flags)
            @

            still indexes contains 0 items... and even worse - no matches even if type string from the begging..
            I suspect that I am not settings flags correctly...

            my data() method returns String for DisplayRole...

            1 Reply Last reply
            0
            • M Offline
              M Offline
              mvidelgauz
              wrote on last edited by
              #8

              Yes, flags should be Qt.MatchFlags(Qt.MatchContains | Qt.MatchWrap)
              (method name 'setFilterFixedString' confused me...)

              now 'indexes' are exactly what I expect them to be

              but self.listView.selectionModel().select(index, QItemSelectionModel.Select) has no visual effect - no items actually selected...

              1 Reply Last reply
              0
              • jazzycamelJ Offline
                jazzycamelJ Offline
                jazzycamel
                wrote on last edited by
                #9

                I was just about to suggest MatchContains ;o)

                The indexes needs to belong to which ever model the view is attached to. If you are calling match() on the source model (which you shouldn't need to, the proxy will be fine as per example) then you will have to map them back to the proxy using mapFromSource().

                For the avoidance of doubt:

                1. All my code samples (C++ or Python) are tested before posting
                2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  mvidelgauz
                  wrote on last edited by
                  #10

                  Thank you again )))

                  no, as I mentioned in previous post I removed sourceModel(). call from code

                  'self.listModel' is what ListView is attached to

                  something is wrong with my ListView itself (regardless to code being discussed) - It doesn't select rows even when I click on them...

                  1 Reply Last reply
                  0
                  • M Offline
                    M Offline
                    mvidelgauz
                    wrote on last edited by
                    #11

                    Anyway, the original question is answered by jazzycamel

                    How do I mark this topic [SOLVED]?

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #12

                      Hi,

                      Simply edit the thread title and add [solved] to it :)

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        mvidelgauz
                        wrote on last edited by
                        #13

                        Thank you SGaist! :)

                        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