alphanumeric
alphanumeric

Reputation: 19329

How to set QSortFilterProxyModel correctly

The code below creates a window with two views: QListView on a left and QTreeView on a right. Both views share the same Model() which sub-classed from QAbstractTableModel. I want left QListView to display the self.modelDict dictionary keys. While the right-side QTreeView to display the dictionary values. I have been recommended to use QSortFilterProxyModel to get things done. I would appreciate if you show how to implement QSortFilterProxyModel into this code:

enter image description here

import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}

class Model(QtCore.QAbstractTableModel):
    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)
        self.modelDict={}    
        self.items=[]
    def rowCount(self, parent=QtCore.QModelIndex()):
        return len(self.items)   
    def columnCount(self, index=QtCore.QModelIndex()):
        return 3
    def data(self, index, role):
        if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
        if role==QtCore.Qt.DisplayRole: return self.items[index.row()]

    def addItem(self, itemName=None, column=0):
        totalItems=self.rowCount()
        self.beginInsertRows(QtCore.QModelIndex(), totalItems+1, column)
        if not itemName:            itemName='Item %s'%self.rowCount()
        self.items.append(itemName)
        self.endInsertRows()

    def buildItems(self):
        (self.addItem(key) for key in self.modelDict)

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        mainLayout=QtGui.QHBoxLayout()
        self.setLayout(mainLayout)   

        self.model=Model()
        self.model.modelDict=elements
        self.model.buildItems()        

        self.viewA=QtGui.QListView()
        self.viewA.setModel(self.model)
        self.viewB=QtGui.QTableView() 
        self.viewB.setModel(self.model)

        mainLayout.addWidget(self.viewA)
        mainLayout.addWidget(self.viewB)    
        self.show()

window=Window()
sys.exit(app.exec_())

Upvotes: 1

Views: 1563

Answers (1)

Ezee
Ezee

Reputation: 4344

Create QSortFilterProxyModel:

self.proxy = QSortFilterProxyModel()

Assign a base model to the proxy:

self.proxy.setSourceModel(self.model)

Make the proxy filter use the first column of the model:

self.proxy.setFilterKeyColumn(0)

Assign the proxy to the table instead of the model:

self.viewB.setModel(self.proxy)

When current index in the first view is changed (connect to signal activated), change the filter key:

self.proxy.setFilterRegExp(self.model.data(self.viewA.currentIndex()).toString())

viewB will display data filtered by the value of an item selected in viewA

Also

  • you have wrong implementation of method data in the model. It never returns values, only keys.
  • self.items also contains only keys.

Depending on how do you want to display values - in 3 rows 1 column or in 3 columns 1 row - these should be fixed.

For example, if you want to display values in 1 row 3 columns, you need to have something like this in your data method:

 if role==QtCore.Qt.DisplayRole: return self.items[index.row()][index.column()]

Upvotes: 4

Related Questions