Цепочки QSortFilterProxyModels

Допустим, у меня есть переменная списка datalist, в которой хранится 10 000 строковых объектов. QTableView необходимо отображать только некоторые из этих объектов. Вот почему QTableView был назначен QSortFilterProxyModel, который выполняет всю фильтрацию. После того, как вся работа с прокси завершена, QTableView "получает" 25 объектов для отображения (поэтому оставшиеся 9 975 объектов были "отфильтрованы").

Теперь я создаю QLineEdit для использования в качестве поля поиска, где пользователь может ввести ключевое слово, чтобы еще больше сузить список отображаемых 25 объектов (элементов). Для этой цели я связываю сигнал textChanged QLineEdit с назначенным методу filterAcceptsRow() QTableView Proxy.

Проблема, которую я здесь вижу, заключается в том, что прокси-модели необходимо вернуться к исходному длинному списку из 10 000 сущностей для повторной фильтрации. И снова. И снова.

Интересно, можно ли создать второй прокси, который будет собирать то, что уже отфильтровал первый прокси: 25 сущностей вместо 10 000.

Таким образом, результирующая схема будет выглядеть так:

datalist > QAbstractTableModel > QSortFilterProxyModel > QSortFilterProxyModel > QTableView

Где:

datalist — переменная длинного списка из 10 000 объектов.

QAbstractTableModel — базовая модель данных

QSortFilterProxyModel — первая прокси-модель, выполняющая самую грязную и медленную работу по фильтрации.

QSortFilterProxyModel — это вторая прокси-модель, работающая с предварительно отфильтрованными данными первого прокси (используется для фильтрации по ключевому слову пользователя).

QTableView — это сам QTableView, используемый для отображения элементов сущности.

Итак, вопрос: правильная ли это идея?


person alphanumeric    schedule 16.01.2015    source источник
comment
Наивно, поскольку QSortFilterProxyModel.setSourceModel(model) предполагает, что передаваемая модель является подклассом QAbstractItemModel, а QSortFilterProxyModel является подклассом QAbstractItemModel, ваша идея должна по крайней мере работать без ошибок. Если вы получите ускорение, которое вы ищете, я не уверен. Определенно стоит собрать минимальный тестовый пример и попробовать!   -  person three_pineapples    schedule 16.01.2015


Ответы (1)


В приведенном ниже коде используются две 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_())

Вот один прокси-подход. Поиск по ключевому слову заметно медленнее по сравнению с реализацией двух прокси:

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_()) 
person alphanumeric    schedule 16.01.2015