Как получить текущие отфильтрованные элементы внутреннего метода filterAcceptsRow в QSortFilterProxyModel - PullRequest
0 голосов
/ 14 апреля 2020

Чтобы отфильтровать TreeView с двумя уровнями (см. Изображение ниже), я использовал класс QSortFilterProxyModel, который имеет QStandardItemModel в качестве исходной модели.

, чтобы игнорировать фильтрацию узлов root, я перегружен метод filterAcceptsRow() выглядит следующим образом.

это мой основной проект, работающий с копированием / вставкой кода ниже класса модели, я заменил импорт данных из базы данных на словарь фиктивных данных

import  sys
from PyQt5 import QtWidgets,QtGui
from PyQt5.QtCore import  QSortFilterProxyModel


services =[{'id':1,'chanel_name':'France 24','satId':0},
           {'id':2,'chanel_name':'Eurosport 02','satId':0},
           {'id':3,'chanel_name':'CANAL +','satId':0},
           {'id':4,'chanel_name':'Eurosport 02','satId':0},
           {'id':5,'chanel_name':'TV 5','satId':0},
           {'id':6,'chanel_name':'BBC World','satId':0},
           {'id':7,'chanel_name':'M6','satId':0},
           {'id':15,'chanel_name':'TEVA','satId':0},
           {'id':8,'chanel_name':'PLANETTE','satId':1},
           {'id':9,'chanel_name':'France 2','satId':1},
           {'id':10,'chanel_name':'France 3','satId':1},
           {'id':11,'chanel_name':'MBC 1','satId':1},
           {'id':12,'chanel_name':'NIL TV','satId':1},
           {'id':13,'chanel_name':'M2','satId':1},
           {'id':14,'chanel_name':'CANAL 02','satId':1},
           {'id':15,'chanel_name':'CHANEL 1','satId':2},
           {'id':8,'chanel_name':'CINE+ FAMILY','satId':2},
           {'id':9,'chanel_name':'OCS CITY','satId':2},
           {'id':10,'chanel_name':'OCS CHOCS','satId':2},
           {'id':11,'chanel_name':'ACTION','satId':2},
           {'id':12,'chanel_name':'NATIONAL GEO','satId':2},
           {'id':13,'chanel_name':'TVEA','satId':2},
           {'id':14,'chanel_name':'CANAL 02','satId':2},

]

class ProxyServiceBySatModel(QSortFilterProxyModel):
    def __init__(self,):
        super().__init__()


    def filterAcceptsRow(self, source_row, source_parent):
        index = self.sourceModel().index(source_row,0,source_parent)
        if  not source_parent.isValid():
             return  True
        else:
            return QSortFilterProxyModel.filterAcceptsRow(self,source_row, source_parent)



class ServicesBySat(QtGui.QStandardItemModel):
    def __init__(self):
        super(ServicesBySat,self).__init__()
        self.setHorizontalHeaderLabels(['Sat name'])
        self.satellite = ['ASTRA 19° E','HotBird 13°','NILSAT 7° W']

    def importData(self, root=None):
        sats= {}
        root = self.invisibleRootItem()
        for service in services:

            sat = service['satId']

            if sat not in sats:
                parent = root
                parent.appendRow(QtGui.QStandardItem(self.satellite[sat]))
                sats[sat] = parent.child(parent.rowCount() - 1)
            else:
                parent = sats[sat]
                parent.appendRow(QtGui.QStandardItem(service['chanel_name']))


class MainWindowISE(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Tree search')
        self.setGeometry(100,100,300,300)
        self.setupUi()
        self.model = ServicesBySat()
        self.model.importData()
        self.proxyModel = ProxyServiceBySatModel()
        self.proxyModel.setSourceModel(self.model)
        self.proxyModel.setFilterKeyColumn(-1)
        self.treeView_services.setModel(self.proxyModel)
        self.lineEdit_Search.textEdited.connect(self.on_lineEditSearch_textEdited)




    def setupUi(self):
        self.gridLayout = QtWidgets.QGridLayout(self)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.label = QtWidgets.QLabel("Search : ", self)
        self.horizontalLayout.addWidget(self.label)
        self.lineEdit_Search = QtWidgets.QLineEdit(self)
        self.horizontalLayout.addWidget(self.lineEdit_Search)
        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
        self.treeView_services = QtWidgets.QTreeView(self)
        self.gridLayout.addWidget(self.treeView_services, 1, 0, 1, 1)



    def on_lineEditSearch_textEdited(self):
        self.proxyModel.setFilterRegularExpression(self.lineEdit_Search.text())


def main():
    app = QtWidgets.QApplication(sys.argv)
    window =MainWindowISE()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

фильтрация работает хорошо, но теперь, чтобы улучшить поведение моего фильтра, я хочу скрыть узлы root, которые не имеют дочерних элементов, в фильтрованных элементах, добавив условие, подобное этому, учитывая, что self - мой прокси модель.

Например, как показано в представлении ниже, я не хочу отображать элемент NILESAT, поскольку у него нет дочерних элементов, соответствующих шаблону фильтра

enter image description here

Я изменил свой метод следующим образом, чтобы достичь ожидаемого результата, но безуспешно.

class ProxyServiceBySatModel (QSortFi lterProxyModel): def init (self,): super (). init ()

def filterAcceptsRow(self, source_row, source_parent):
    index = self.sourceModel().index(source_row,0,source_parent)
    if  not source_parent.isValid() and self.hasChildren(index) :
         return  True
    else:
        return QSortFilterProxyModel.filterAcceptsRow(self,source_row, source_parent)

или я могу использовать это условие, но получить тот же результат ,

if  not source_parent.isValid() and self.rowCount(index) > 0 :

но я получаю исключение

QSortFilterProxyModel: индекс из неверной модели передан в mapToSource

как можно получить текущую строку Подсчет или значение hasChildren внутреннего метода filterAcceptsRow или другой способ достижения ожидаемого результата.

...