如何优化 PyQt QSortFilterProxyModel 过滤器重新实现?
我有一个重新实现的 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 秒,我想知道是否有更好的方法。
PD:这个类基本上是我在 KDE websvn
I have a reimplemented QSortFilterProxyModel acceptRows to achieve custom behavior, i want it to not filter out items which have a valid child.
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
However this aproach doesn't seems to be efficient because with 300 items it takes almost 3 seconds to update the view, i want to know if theres a better way of doing it.
PD: This class is basically a translation of a KSysGuard one i found in KDE websvn
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不认为你所做的事情有任何明显的错误。请记住,模型中的每个项目都会调用
filterAcceptsRow
,这当然会很慢,因为从 C++ 调用 Python 函数的开销很小毫秒。如果您的模型包含数百个项目,那么这个数字会很快增加。再加上从 Python 调用的 C++ 函数的数量,您很容易就会注意到您注意到的 3 秒。此外,
QTableView
和QSortFilterProxyModel
做了很多聪明的事情来将它们发出的信号和所需的更新量保持在最低限度。遗憾的是,如果在过滤器重置后删除或添加的行非常分散在模型中,这会导致非常糟糕的性能。在我们的项目中,我们决定用 C++ 实现大多数基于项目的模型,至少对于那些为包含大量行或列的模型中的每个项目调用的方法。但是,这可能不是您正在寻找的答案,特别是如果您的更新延迟是由连接到同一模型的其他信号处理程序引起的。发出信号通常与调用方法相同。
简而言之,您最好使用探查器来查看您的应用程序在何处花费了大部分时间,如果模型中的每个项目在这些方法中调用一次(甚至多次),则最好使用 C++。
I don't see anything obviously wrong with what you're doing. Keep in mind that
filterAcceptsRow
is called for every item in your model, and this is of course going to be sluggish because the overhead of calling a Python function from C++ is a few milliseconds. This adds up rather quickly if you have a model with a few hundred items. Add to this the amount of C++ functions called from Python, and you can easily end up with the 3 seconds you're noticing.Also,
QTableView
andQSortFilterProxyModel
do an awful lot of clever things to keep the signals they emit and the amount of updates required to a minimum. Sadly, this leads to very bad performance if the rows that are removed or added after a filter reset are very much scattered over your model.In our projects, we have made the decision to implement most of these item-based models in C++, at least for those methods that are called for every item in a model that contains more than a trivial amount of rows or columns. However, this may not be the answer you're looking for, especially if your update delays are caused by e.g. other signal handlers connected to the same model. Emitting a signal is usually the same as calling a method.
In short, you'd best use a profiler to see where your application is spending most of its time, and use C++ if it is in these methods that are called once (or even more than once) per item in your model.