Chained QSortFilterProxyModels

六月ゝ 毕业季﹏ 提交于 2019-12-09 12:28:34

问题


Let's say I have a list variable datalist storing 10,000 string entities. The QTableView needs to display only some of these entities. That's is why QTableView was assigned QSortFilterProxyModel that does all the filtering. After all Proxy work is completed the QTableView "receives" 25 entities to display (so remaining 9,975 entities were "filtered out".

Now, I create a QLineEdit to be used as a search field where the user can type a keyword to narrow down the list of the displayed 25 entities (items) even further. For this purpose I link QLineEdit's textChanged signal to assigned to QTableView Proxy's filterAcceptsRow() method.

The problem I see here is that Proxy model needs to get back to the original 10,000 entities long list to re-filter once again. And again. And again.

I wonder if it is possible to create a second Proxy that would pickup what the first Proxy has already filtered out: 25 entities instead of 10,000.

So the resulting schema would look like this:

datalist > QAbstractTableModel > QSortFilterProxyModel > QSortFilterProxyModel > QTableView

Where:

datalist is 10,000 entities long list variable.

QAbstractTableModel is a base data model

QSortFilterProxyModel is a first Proxy Model doing the dirtiest and slowest filtering job

QSortFilterProxyModel is a second Proxy Model working on a pre-filtered by first Proxy data (it is used to filter by the user's keyword).

QTableView is a QTableView itself used to display the entity items.

So, the question is: is it a valid idea?


回答1:


The code below uses two ProxyModels filtering 10,000 items. It works...

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

class MyTableModel(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = [i for i in range(10000)]

    def rowCount(self, parent):
        return len(self.items)       
    def columnCount(self, parent):
        return 1

    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        column=index.column()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

class Proxy01(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy01, self).__init__()
    def filterAcceptsRow(self, row, parent):        
        sourceModel=self.sourceModel()
        index=sourceModel.index(row, 0, parent)
        name=sourceModel.data(index, Qt.DisplayRole).toString()

        if name and not int(name)%10:
            return True
        return False

class Proxy02(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy02, self).__init__()
        self.keyword=None

    def setKeyword(self, arg):
        if arg: self.keyword=str(arg)
        self.reset()    

    def filterAcceptsRow(self, row, parent):
        sourceModel=self.sourceModel().sourceModel()
        index=sourceModel.index(row, 0, parent)
        name=sourceModel.data(index, Qt.DisplayRole).toString()

        if self.keyword and name and not self.keyword.lower() in str(name).lower():
            return False        
        return True

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        self.tablemodel=MyTableModel(self)               

        self.proxy1=Proxy01()
        self.proxy1.setSourceModel(self.tablemodel)

        self.proxy2=Proxy02()
        self.proxy2.setSourceModel(self.proxy1)

        tableviewA=QTableView() 
        tableviewA.setModel(self.proxy2)

        searchEdit=QLineEdit()
        searchEdit.textChanged.connect(self.proxy2.setKeyword)

        layout = QVBoxLayout(self)
        layout.addWidget(tableviewA)
        layout.addWidget(searchEdit)
        self.setLayout(layout)

    def test(self, arg):
        print arg

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

Here is a single Proxy approach. Searching by keyword is noticably slower vs two proxys implementation:

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

class MyTableModel(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = [i for i in range(10000)]

    def rowCount(self, parent):
        return len(self.items)       
    def columnCount(self, parent):
        return 1

    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        elif role != Qt.DisplayRole:
            return QVariant()

        row=index.row()
        column=index.column()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

class Proxy01(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy01, self).__init__()
        self.keyword=None

    def setKeyword(self, arg):
        if arg: self.keyword=str(arg)
        self.reset()    

    def filterAcceptsRow(self, row, parent):
        sourceModel=self.sourceModel()
        index=sourceModel.index(row, 0, parent)
        name=sourceModel.data(index, Qt.DisplayRole).toString()

        if self.keyword and name and not self.keyword.lower() in str(name).lower():
            return False        
        return True

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        self.tablemodel=MyTableModel(self)               

        self.proxy1=Proxy01()
        self.proxy1.setSourceModel(self.tablemodel)

        tableviewA=QTableView() 
        tableviewA.setModel(self.proxy1)

        searchEdit=QLineEdit()
        searchEdit.textChanged.connect(self.proxy1.setKeyword)

        layout = QVBoxLayout(self)
        layout.addWidget(tableviewA)
        layout.addWidget(searchEdit)
        self.setLayout(layout)

    def test(self, arg):
        print arg

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_()) 


来源:https://stackoverflow.com/questions/27975594/chained-qsortfilterproxymodels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!