链式 QSortFilterProxyModels

Chained QSortFilterProxyModels

假设我有一个列表变量 datalist 存储 10,000 个字符串实体。 QTableView 只需要显示其中的一些实体。这就是为什么 QTableView 被指定 QSortFilterProxyModel 来执行所有过滤的原因。 所有代理工作完成后 QTableView "receives" 25 个实体要显示(因此剩余的 9,975 个实体是 "filtered out".

现在,我创建了一个 QLineEdit 用作搜索字段,用户可以在其中键入关键字以进一步缩小显示的 25 个实体(项目)的列表。为此,我将 link QLineEdittextChanged 信号分配给 QTableView Proxy 的 filterAcceptsRow() 方法。

我在这里看到的问题是 Proxy 模型需要回到原来的 10,000 个实体长列表来再次重新过滤。然后再次。再一次。

我想知道是否可以创建第二个代理来拾取第一个代理已经过滤掉的内容:25 个实体而不是 10,000 个。

因此生成的架构如下所示:

datalist > QAbstractTableModel > QSortFilterProxyModel > QSortFilterProxyModel > QTableView

其中:

datalist 是 10,000 个实体长列表变量。

QAbstractTableModel 是基础数据模型

QSortFilterProxyModel 是第一个执行最脏和最慢过滤工作的代理模型

QSortFilterProxyModel 是第二个代理模型,它处理由第一个代理数据预过滤的数据(用于按用户关键字过滤)。

QTableView是一个QTableView本身,用于显示实体项。

所以,问题是:这是一个有效的想法吗?

下面的代码使用两个 ProxyModels 过滤 10,000 个项目。有用...

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_())

这是一个单一的Proxy方法。与两个代理实施相比,按关键字搜索明显更慢:

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_())