[PyQt] Performance problems with QSortFilterProxyModel

Steve Borho steve at borho.org
Sat May 15 05:12:46 BST 2010


On Thu, May 13, 2010 at 5:01 AM, Mark Summerfield <list at qtrac.plus.com> wrote:
> On 2010-05-12, Steve Borho wrote:
>> On Wed, May 12, 2010 at 1:04 AM, Mark Summerfield <list at qtrac.plus.com>
> wrote:
>> > On 2010-05-12, Steve Borho wrote:
>> >> Hello,
>> >>
>> >> The TortoiseHg project is currently porting all of our PyGTK apps to
>> >> PyQt, This has been going pretty well so far, but I've hit a snag with
>> >> our file status browser.
>> >>
>> >> I have a simple QAbstractTableModel (4 columns) being displayed in a
>> >> QTreeView.  After connecting a QSortFilterProxyModel between the tree
>> >> view and the data model, reloading the model became very expensive for
>> >> moderately sized data sets.  After calling setSourceModel() with a
>> >> model of 555 rows, I counted over 3 million calls to the model data()
>> >> method, which takes about 15 seconds.
>> >
>> > Have you tried switching off sorting just before resetting the model and
>> > then switching it back on afterwards?
>>
>> I just tried with this:
>>
>>   tm = MyTableModel(data)
>>   tv.setSortingEnabled(False)
>>   proxy.setSourceModel(tm)
>>   tv.setSortingEnabled(True)
>>
>> But it made no performance difference.
>
> Then maybe no sorting took place?
>
> When you call QAbstractTableView.setSortingEnabled(True), Qt is supposed
> to call QAbstractTableView.sortByColumn() to perform the sort. But
> sortByColumn() will only have an effect if the model is sortable, that
> is, if the QAbsractItemModel you're using has reimplemented the sort()
> method (since the base class version does nothing).
>
> Things are slightly different if you use a QSortFilterProxyModel of
> course, since that provides an implementation of
> QAbsractItemModel.sort(). So in the example you've shown the proxy
> should do the sorting.
>
> But I guess you're saying "yes it sorted---but it was just as slow"?
>
> However, you don't mention where the model gets set on the view? Does
> this make a difference:
>
>    # tv has no model at this point
>    tm = MyTableModel(data)
>    tv.setSortingEnabled(False)
>    proxy.setSourceModel(tm)
>    tv.setModel(proxy) # now tv has a model
>    tv.setSortingEnabled(True)

I did just try this and it had no effect on the performance.  As soon
as control is returned
to the main event loop, it performs millions of model.data() calls.

> Using QSortFilterProxyModel can adversely affect performance. So one
> solution is to try to avoid using it, i.e., by reimplementing the sort()
> method in your custom QAbstractTableModel.

This was what I ended up doing.  It was actually pretty painless.

> Another solution is to get
> the correct ordering without sorting at all by using intrinsically
> ordered data structures.

The sort itself is pretty fast now; but I did re-order a few lines to
make sure the sort is only performed once when a model is first
created.

--
Steve Borho


More information about the PyQt mailing list