如何优化PyQt QSortFilterProxyModel的过滤器重实现?

2 投票
1 回答
3624 浏览
提问于 2025-04-16 02:44

我重新实现了QSortFilterProxyModel的acceptRows方法,目的是让它在过滤时不把那些有有效子项的项目过滤掉。

class KSortFilterProxyModel(QSortFilterProxyModel):
    #FIXME: Funciona pero es endemoniadamente lento
    def __init__(self, parent=None):
        super(KSortFilterProxyModel, self).__init__(parent)
        self.__showAllChildren = False

    def showAllChildren(self):
        return self.__showAllChildren;

    def setShowAllChildren(self, showAllChildren):
        if showAllChildren == self.__showAllChildren:
            return
        self.__showAllChildren = showAllChildren
        self.invalidateFilter()

    def filterAcceptsRow (self, source_row, source_parent ):
        if self.filterRegExp() == "" :
            return True #Shortcut for common case

        if  super(KSortFilterProxyModel, self).filterAcceptsRow( source_row, source_parent) :
            return True

        #one of our children might be accepted, so accept this row if one of our children are accepted.
        source_index = self.sourceModel().index(source_row, 0, source_parent)
        for i in range( self.sourceModel().rowCount(source_index)):
            if self.filterAcceptsRow(i, source_index):
                return True

        return False

不过,这种做法似乎效率不高,因为在处理300个项目时,更新视图几乎要花3秒钟。我想知道有没有更好的方法来做到这一点。

附注:这个类基本上是我在KDE websvn找到的KSysGuard类的翻译。

1 个回答

1

我觉得你做的事情没有明显的问题。不过要记住,filterAcceptsRow这个函数会对你模型里的每一个项目都调用一次,这样会比较慢,因为从C++调用Python函数需要花费几毫秒的时间。如果你的模型里有几百个项目,这个时间就会累积得很快。再加上从Python调用的C++函数,你可能会发现程序的延迟达到了3秒。

另外,QTableViewQSortFilterProxyModel做了很多聪明的事情,目的是为了减少它们发出的信号和需要更新的次数。但可惜的是,如果在过滤器重置后,移除或添加的行在模型中分布得很散,这样会导致性能变得很差。

在我们的项目中,我们决定把大部分基于项目的模型用C++实现,特别是那些在包含很多行或列的模型中,每个项目都会调用的方法。不过,这可能不是你想要的答案,尤其是如果你的更新延迟是因为其他信号处理程序连接到了同一个模型。发出一个信号通常和调用一个方法是一样的。

总之,最好使用性能分析工具来查看你的应用程序大部分时间花在哪里,如果是在那些每个项目都会调用一次(或者更多次)的方法中,就用C++来实现。

撰写回答