[PyQt] QSortFilterProxyModel::sort() not sorting on column types
J Barchan
jnbarchan at gmail.com
Tue Feb 5 09:06:32 GMT 2019
On Fri, 1 Feb 2019 at 20:50, Maurizio Berti <maurizio.berti at gmail.com>
wrote:
> To correctly support sorting for non string values you need to provide
> your own method.
> Also, for numeric values ensure that the data is stored as a number and
> not as string. For QStandardItemModel you can achieve that by creating
> QStandardItems without any data value, and then set the numeric data using
> QStandardItem.setData(value, QtCore.Qt.DisplayValue); remember that the
> role must be specified, as the setData method of QStandardItem uses the
> UserRole + 1 role by default. This will solve the sorting for your float
> column.
>
> To sort by date, it's better to set the QDateTime value as a custom role
> (>=UserRole) and store the object as it is, while you can choose to set the
> displayed string once you create the QStandardItems or by using an item
> delegate, if you need a visual representation.
> After that just implement the lessThan() method of QSortFilterProxyModel,
> which allows to customize how the items are sorted whenever the sort()
> method is called.
>
> Supposing that you're using the second column for the QDateTime items and
> you're using a role DateRole = QtCore.Qt.UserRole + 1:
>
> class SortModel(QtCore.QSortFilterProxyModel):
> def lessThan(self, left, right):
> if left.column() == right.column() and left.column() == 1:
> return left.data(DateRole) < right.data(DateRole)
> return QtCore.QSortFilterProxyModel.lessThan(self, left, right)
>
> class MyWidget(QtWidgets.QWidget):
> def __init__(self, *args, **kwargs):
> QtWidgets.QWidget.__init__(self, *args, **kwargs)
> [...]
> self.sourceModel = QtGui.QStandardItemModel()
> self.sortModel = SortModel()
> self.someTable.setModel(self.sortModel)
> self.sortModel.setSourceModel(self.sourceModel)
>
> def appendFields(self):
> floatItem = QtGui.QStandardItem()
> floatItem.setData(self.getSomeFloatNumber(), QtCore.Qt.DisplayRole)
> someDate = QtCore.QDateTime.currentDateTime()
> item = QtGui.QStandardItem(someDate.toString())
> item.setData(someDate, DateRole)
> self.sourceModel.appendRow([floatItem, dateItem])
>
> I've tested it on an old 5.7.1, but from what you are experiencing it is
> not a bug, but the expected behavior, since you didn't correctly implement
> the sorting method and/or didn't provide a correct way for Qt to interpret
> data for its default sorting rules.
>
> Regards,
> Maurizio
>
>
>
> Il giorno ven 1 feb 2019 alle ore 10:45 J Barchan <jnbarchan at gmail.com>
> ha scritto:
>
>> I use Qt/PyQt 5.7, the standard distribution supplied for Ubuntu 18.04.
>>
>> I have a QSortFilterProxyModel wrapped around a QStandardItemModel as
>> its source model. I try to use QSortFilterProxyModel::sort() to sort by
>> column values.
>>
>> I have a column of Python type datetime.date. When I call the sort(),
>> there is no "warning" but *nothing happens*. The sort does not
>> rearrange the items at all. They are initially "randomly" ordered in rows,
>> and the rows simply retain their current order. It does *not* even
>> reorder by string value. It is as though it simply decides they are
>> "unorderable".
>>
>> When I sort instead by a Python str column they *do* get reordered.
>> FWIW, I have another column of Python type decimal.Decimal and sorting
>> by that too does nothing, even though I think that should be convertible to
>> float/double. However, that may complicate matters so let's stick to
>> the datetime.date case, I am just mentioning it in case it's relevant.
>>
>> It took me a long time to realise where the problem lies. I have a
>> workaround: I *explicitly* change all my values in the model from
>> datetime.date to QDate(value) and now it does sort.
>>
>> But my understanding/experience from other PyQt methods is that it does
>> this kind of Python type -> QVariant conversion for you behind the
>> scenes itself. I shouldn't have to change my types or write special code.
>>
>> Is this a bug? Is this in my PyQt 5.7 only?
>>
>> --
>> Kindest,
>> Jonathan
>> _______________________________________________
>> PyQt mailing list PyQt at riverbankcomputing.com
>> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>>
>
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
>
Thank you for replying, Maurizio. It has taken me a few days to get back
to this.
While I have no argument with your detailed reply (I'm quite sure you know
much than I do), I do not understand *why* any of this necessary, and would
appreciate any clarification.
To correctly support sorting for non string values you need to provide your
> own method.
>
If I did not make it clear I would remind you of one of my findings. I
start with Python datetime.date variables. I populate the model via
setData(index,
dateValue) (no role specified, so EditRole). At this point no sorting
happens. However, all I have to do is change that to setData(index,
QDate(dateValue)) and it *does* then work, so no "need to provide your own
method".
Why is that? From http://doc.qt.io/qt-5/qsortfilterproxymodel.html#lessThan
I am told that the sorting deals in QVariant types, and QMetaType::QDate is
among those it handles. Now, you know much better than I, but everywhere
else I use PyQt it seems to convert between Python types and necessary
QVariant types invisibly and all is well, but not here? Why not?
I'm also a little lost about QStandardItem vs QStandardItemModel, if that's
significant. My code creates the (source) model as a QStandardItemModel.
That claims to use http://doc.qt.io/qt-5/qstandarditemmodel.html#setData,whose
default role is EditRole. Nowhere do I create a QStandardItem explicitly,
whose http://doc.qt.io/qt-5/qstandarditem.html#setData uses default
role is UserRole
+ 1. So now I'm not sure which I am using, though I would think only
QStandardItemModel? Is this of relevance to my issue?
Thank you for any explanation.
--
Kindest,
Jonathan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190205/5c04af84/attachment-0001.html>
More information about the PyQt
mailing list