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 access source model methods from Proxy model
QtWS25 Last Chance

How to access source model methods from Proxy model

Scheduled Pinned Locked Moved Solved Qt for Python
10 Posts 2 Posters 4.7k 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.
  • H Offline
    H Offline
    hachbani
    wrote on last edited by
    #1

    Hello,

    I'm using Pyside2 with python 3.8.

    I'm trying to figure out how to set up a proxy model to my qtableview. At a first glance, I'm just trying to set up the proxy model without overriding the filterAcceptsRow() method. Just to get a first understanding of how the sortfilterproxymodel works.

    Here's my Proxy model class:

    class ProxyModel(QtCore.QSortFilterProxyModel):
    	def __init__(self,parent=None):
    		super(ProxyModel, self).__init__()
    		self.filter = (0,0)
    
    	def mapFromSource(self, index):
    		return self.createIndex(index.row(), index.column())
    
    	def mapToSource(self, index):
    		return self.sourceModel().index(index.row(), index.column(), QtCore.QModelIndex())
    
    	def Filtre(self, column, valeur):
    		self.filter = (column, valeur)
    

    in the MainWindow class, I have did the folliwing lines of code:

    ProxyModel = ProxyModel()
    Model = TableModel() 
    
    ProxyModel.setSourceModel(Model)
    self.MyTableView.setModel(ProxyModel)
    

    I have several methods in my TableModel() class, which subclass from QAbstractTableModel. Let's say now I want to set up my headers, Before Implementing the proxymodel, the following line would work:

    self.MyTableView.model().set_headers(self.headers)
    

    Where set_headers() is my method and self.headers is a list of column's headers.

    After Implementing the ProxyModel() class, This doesn't work: it says that ProxyModel object has no attribute set_headers. Which makes sense because I think now, the algorithm goes in PorxyModel and search for a method called set_headers. I thought that since It's a proxy model, It kind of works automatically that the code would go to the source model looking for the method.

    Definitely, I'm doing it wrong, and all my other source model methods that I'm calling are not going to work. Unless I fix it.

    setting up Proxy models is all new to me, and I'm still missing on several basics even though after reading tons of documentation.

    Can any one give me any more insight on this please ?

    Here's a glimpse of my TableModel class, if ever you need it:

    class TableModel(QtCore.QAbstractTableModel):
    
    	def __init__(self, mlist=None):
    		super(TableModel, self).__init__()
    		self._items = [] if mlist == None else mlist
    		self._header = []
    
    	def rowCount(self, parent = QtCore.QModelIndex):
    		return len(self._items)
    
    	def columnCount(self, parent = QtCore.QModelIndex):
    		return len(self._header)
    
    	def data(self, index, role = QtCore.Qt.DisplayRole):
    		if not index.isValid():
    		   return None
    		if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
    			return self._items[index.row()][index.column()]
    		return None
    	
    	def setData(self, index, value, role = QtCore.Qt.EditRole):
    		if value is not None and role == QtCore.Qt.EditRole:
    			self._items[index.row()-1][index.column()] = value
    			self.dataChanged.emit(index, index)
    			return True
    		return False
    
    	def addRow(self, rowObject):
    		row = self.rowCount()
    		self.beginInsertRows(QtCore.QModelIndex(), row, row)
    		self._items.append(rowObject)
    		self.endInsertRows()
    		self.layoutChanged.emit()
    

    Thanks,

    JonBJ 1 Reply Last reply
    0
    • H hachbani

      Hello,

      I'm using Pyside2 with python 3.8.

      I'm trying to figure out how to set up a proxy model to my qtableview. At a first glance, I'm just trying to set up the proxy model without overriding the filterAcceptsRow() method. Just to get a first understanding of how the sortfilterproxymodel works.

      Here's my Proxy model class:

      class ProxyModel(QtCore.QSortFilterProxyModel):
      	def __init__(self,parent=None):
      		super(ProxyModel, self).__init__()
      		self.filter = (0,0)
      
      	def mapFromSource(self, index):
      		return self.createIndex(index.row(), index.column())
      
      	def mapToSource(self, index):
      		return self.sourceModel().index(index.row(), index.column(), QtCore.QModelIndex())
      
      	def Filtre(self, column, valeur):
      		self.filter = (column, valeur)
      

      in the MainWindow class, I have did the folliwing lines of code:

      ProxyModel = ProxyModel()
      Model = TableModel() 
      
      ProxyModel.setSourceModel(Model)
      self.MyTableView.setModel(ProxyModel)
      

      I have several methods in my TableModel() class, which subclass from QAbstractTableModel. Let's say now I want to set up my headers, Before Implementing the proxymodel, the following line would work:

      self.MyTableView.model().set_headers(self.headers)
      

      Where set_headers() is my method and self.headers is a list of column's headers.

      After Implementing the ProxyModel() class, This doesn't work: it says that ProxyModel object has no attribute set_headers. Which makes sense because I think now, the algorithm goes in PorxyModel and search for a method called set_headers. I thought that since It's a proxy model, It kind of works automatically that the code would go to the source model looking for the method.

      Definitely, I'm doing it wrong, and all my other source model methods that I'm calling are not going to work. Unless I fix it.

      setting up Proxy models is all new to me, and I'm still missing on several basics even though after reading tons of documentation.

      Can any one give me any more insight on this please ?

      Here's a glimpse of my TableModel class, if ever you need it:

      class TableModel(QtCore.QAbstractTableModel):
      
      	def __init__(self, mlist=None):
      		super(TableModel, self).__init__()
      		self._items = [] if mlist == None else mlist
      		self._header = []
      
      	def rowCount(self, parent = QtCore.QModelIndex):
      		return len(self._items)
      
      	def columnCount(self, parent = QtCore.QModelIndex):
      		return len(self._header)
      
      	def data(self, index, role = QtCore.Qt.DisplayRole):
      		if not index.isValid():
      		   return None
      		if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
      			return self._items[index.row()][index.column()]
      		return None
      	
      	def setData(self, index, value, role = QtCore.Qt.EditRole):
      		if value is not None and role == QtCore.Qt.EditRole:
      			self._items[index.row()-1][index.column()] = value
      			self.dataChanged.emit(index, index)
      			return True
      		return False
      
      	def addRow(self, rowObject):
      		row = self.rowCount()
      		self.beginInsertRows(QtCore.QModelIndex(), row, row)
      		self._items.append(rowObject)
      		self.endInsertRows()
      		self.layoutChanged.emit()
      

      Thanks,

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @hachbani
      All I think you are missing is that QAbstractProxyModel has a method QAbstractItemModel *QAbstractProxyModel::sourceModel() const. That matches with the ProxyModel.setSourceModel(Model) which you do.

      So to implement your self.MyTableView.model().set_headers(self.headers) you will now want:

      self.MyTableView.model().sourceModel().set_headers(self.headers)
      

      For more advanced scenarios you could use Python's isinstance(self.MyTableView.model(), ProxyModel) if you need to check whether the view's model is a proxy model rather than a direct model.

      Yes, you will have to change other existing code which currently assumes that self.MyTableView.model() == Model because that is no longer the case. Write yourself a method in MyTableView like:

      def tableModel() -> TableModel:
          return self.MyTableView.model().sourceModel()
      

      and use that instead of your self.MyTableView.model(). Or, you could make your Model = TableModel() a member variable and use that directly, depending on your programming preferences.

      1 Reply Last reply
      1
      • H Offline
        H Offline
        hachbani
        wrote on last edited by
        #3

        Thanks for the reply, so for everytime I'm calling a sourceModel, I have to call it from .sourceModel().method, I don't need to reimplement those methods into the proxy model right ?

        JonBJ 1 Reply Last reply
        0
        • H hachbani

          Thanks for the reply, so for everytime I'm calling a sourceModel, I have to call it from .sourceModel().method, I don't need to reimplement those methods into the proxy model right ?

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @hachbani @hachbani
          I had just augmented my previous post with a suggested convenience method (or member variable) for this.

          You do not need to implement QAbstractItemModel methods on the QAbstractProxyModel wrapper, although you could do. I tend not to, it gets to be a potentially large number of methods/signals/slots etc. I think it's cleaner to go through the suggested method which returns the source model from the proxy model and continue to use that as you did before.

          1 Reply Last reply
          0
          • H Offline
            H Offline
            hachbani
            wrote on last edited by
            #5
            This post is deleted!
            1 Reply Last reply
            0
            • H Offline
              H Offline
              hachbani
              wrote on last edited by
              #6

              Hi, Thanks a lot, it worked ! I did as you sad and called the methods using model().sourceModel().

              I'm trying to reimplement my FilterAcceptRows(). here's what I did.

              class ProxyModel(QtCore.QSortFilterProxyModel):
              	def __init__(self,parent=None):
              		super(ProxyModel, self).__init__()
              		self.filter = (3,20)
              
              	def filterAcceptsRow(self, sourceRow, sourceParent):
              		print('im here')
              		sourceModel = self.sourceModel()
              		id = sourceModel.index(sourceRow, self.filter[0], sourceParent)
              
              		if sourceModel.data(id) == self.filter[1]: 
              			return True
              		return False
              

              What I'm trying to do is filter on the 4th column, the rows where the cells(row, 4) is equal to 20.
              The output is a bit weird, it does filter but I don't know what it does filter on. Reading my code, how do you think this is working ?

              JonBJ 1 Reply Last reply
              0
              • H hachbani

                Hi, Thanks a lot, it worked ! I did as you sad and called the methods using model().sourceModel().

                I'm trying to reimplement my FilterAcceptRows(). here's what I did.

                class ProxyModel(QtCore.QSortFilterProxyModel):
                	def __init__(self,parent=None):
                		super(ProxyModel, self).__init__()
                		self.filter = (3,20)
                
                	def filterAcceptsRow(self, sourceRow, sourceParent):
                		print('im here')
                		sourceModel = self.sourceModel()
                		id = sourceModel.index(sourceRow, self.filter[0], sourceParent)
                
                		if sourceModel.data(id) == self.filter[1]: 
                			return True
                		return False
                

                What I'm trying to do is filter on the 4th column, the rows where the cells(row, 4) is equal to 20.
                The output is a bit weird, it does filter but I don't know what it does filter on. Reading my code, how do you think this is working ?

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @hachbani said in How to access source model methods from Proxy model:

                The output is a bit weird,

                I don't know what this means. Your code looks alright to me, you are picking out column #3 in the source row and seeing if that (Qt.DisplayRole) equals 20. Assuming those numbers are correct, it should work, are you saying it does not?

                1 Reply Last reply
                0
                • H Offline
                  H Offline
                  hachbani
                  wrote on last edited by hachbani
                  #8

                  @JonB , Here's my Table without the filterAcceptsRow() reimplementation

                  before.PNG

                  My Table after filtering on 13 as a value in the 4th column (Num It)

                  after.PNG

                  I don't understand.. It's like all what it did is keeping the first 6 lines

                  JonBJ 1 Reply Last reply
                  0
                  • H hachbani

                    @JonB , Here's my Table without the filterAcceptsRow() reimplementation

                    before.PNG

                    My Table after filtering on 13 as a value in the 4th column (Num It)

                    after.PNG

                    I don't understand.. It's like all what it did is keeping the first 6 lines

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #9

                    @hachbani
                    This is because of your (erroneous) overrides of def mapFromSource/mapToSource back in your ProxyModel.

                    Those methods need to map between the different row numbers in your proxy versus source model. Because you are using a QSortFilterProxyModel the row numbers will not match: when filtering the proxy's fist row might be the source's fifth row, and if you add sorting they can all come in a different order anyway.

                    QSortFilterProxyModel knows how to do all of this mapping for you, but you have undone all its work in your definitions, which are actually like a QIdentityProxyModel. Hence it is showing the right number of rows (presumably) but the wrong ones --- there are 6 accepted rows, so it picks numbers 0--5 from the source model!

                    Get rid of those two methods. You never needed to override them in a QSortFilterProxyModel.

                    H 1 Reply Last reply
                    2
                    • JonBJ JonB

                      @hachbani
                      This is because of your (erroneous) overrides of def mapFromSource/mapToSource back in your ProxyModel.

                      Those methods need to map between the different row numbers in your proxy versus source model. Because you are using a QSortFilterProxyModel the row numbers will not match: when filtering the proxy's fist row might be the source's fifth row, and if you add sorting they can all come in a different order anyway.

                      QSortFilterProxyModel knows how to do all of this mapping for you, but you have undone all its work in your definitions, which are actually like a QIdentityProxyModel. Hence it is showing the right number of rows (presumably) but the wrong ones --- there are 6 accepted rows, so it picks numbers 0--5 from the source model!

                      Get rid of those two methods. You never needed to override them in a QSortFilterProxyModel.

                      H Offline
                      H Offline
                      hachbani
                      wrote on last edited by
                      #10

                      @JonB
                      Man, thanks again really, the newbie I'm on this sort of things, you're saving me. I've looking all over the documentations for the past 3 days to do this. Thanks. It works.

                      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