QSortFilterProxyModel - custom lessThan is not being called
-
I have a custom "tree model" class, which is an implementation of
QAbstractItemModel
plus my own custom APIs for updating the model and exposing to QML etc., but I don't think any of that is relevant here.I would like to modify the way it is presented - in particular to sort certain nodes according to certain criteria. So I have created a new "sorted tree model", implementing
QSortFilterProxyModel
. This callssetSourceModel
with my original model, which I hold as a member variable, and I have implemented the same APIs as needed for QML exposure etc by delegating to the original model but usingmapToSource
andmapFromSource
as appropriate. In theory it is a drop in replacement for the original tree model.class SortedModel : public QSortFilterProxyModel { Q_OBJECT public: SortedModel (OrigModel* treeModel, QObject *parent = nullptr); ~MySortedTreeModel() override; ... private: OrigModel* m_treeModel; };
SortedModel::SortedModel(OrigModel* treeModel, QObject* parent) : QSortFilterProxyModel(parent), m_treeModel(treeModel) { setSourceModel(m_treeModel); ... }
Everything I have omitted is concerned with my custom API for QML exposure. As mentioned it just does simple delegation. I have tested this wrapper as a drop in replacement but without trying to implement any sorting and it works as expected.
Then I implemented the
lessThan
override in theSortedModel
and tried to test the sorting functionality I wanted to implement.However, I found that
lessThan
is not being called at all.My understanding is that automatic sorting is on by default (
dynamicSortFilter
) - and that the proxy model detects changes to the source model and adjusts the sorting automatically. I expected that this would cause calls into mylessThan
method to happen but I do not see these. I am sure that the source model is generating all of the necessary model update notifications as (a) it has been in use in its own right as the model for a QMLTreeView
for some time and (b) mySortedModel
also functions fine if used as the QML model as a simple wrapper around the source model but without any sorting implemented.So, my question is: what do I need to do to force the proxy model to sort itself automatically, so that it uses my provided
lessThan
, whenever the underlying model changes? I expected that simply providing the override in my class would be sufficient but it seems that something more is needed. -
@Bob64
dynamicSortFilter
means that sorting will be re-done when the model reports changes.But you have to tell the QSFPM that you actually want it to do any sorting, which column it should sort on. int QSortFilterProxyModel::sortColumn() const
Returns the column currently used for sorting
This returns the most recently used sort column. The default value is -1, which means that this proxy model does not sort.
You have not indicated how or what you have told the QSFPM to sort by, so I don't see why it should ever have called the
lessThan()
.So, my question is: what do I need to do to force the proxy model to sort itself automatically, so that it uses my provided lessThan, whenever the underlying model changes?
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
-
And where / how to you use this model?
-
@JonB no I am not doing that as I had understood that the 'dynamicSortFilter' property is true by default and that sorting happens automatically as a result of that. If I have to call
sort
manually I guess I can arrange for that. I don't understand whatdynamicSortFilter
is for in that case though. -
@Christian-Ehrlicher in reality it gets used in a QML application but I am currently using it the context of a unit test.
In the real system, JSON "nested dictionary" data is received from a server and I have a class that creates/updates the tree model from that. I have written my own updating interface on my model implementation and that call the standard notifications in
QAbstractItemModel
(rows added, data changed and so on). All this works fine and has been doing so for a long time now.I guess my question is really what is the minimum that needs to be done to wrap a
QSortFilterProxyModel
around an existing model such that I can provide a customlessThan
which will be called as needed to keep the model sorted with respect to updates in the underlying model.It sounds from what JonB says that I might need to call
sort
at appropriate points. I intend to try that but it will mean I have misunderstood the documentation aboutdynamicSortFilter
. -
@Bob64
dynamicSortFilter
means that sorting will be re-done when the model reports changes.But you have to tell the QSFPM that you actually want it to do any sorting, which column it should sort on. int QSortFilterProxyModel::sortColumn() const
Returns the column currently used for sorting
This returns the most recently used sort column. The default value is -1, which means that this proxy model does not sort.
You have not indicated how or what you have told the QSFPM to sort by, so I don't see why it should ever have called the
lessThan()
.So, my question is: what do I need to do to force the proxy model to sort itself automatically, so that it uses my provided lessThan, whenever the underlying model changes?
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
-
@JonB so it sounds like I at least need to provide
sortColumn
. That is something I had missed.Just to be clear - as maybe this was what I was missing - is the
sort
call a one off after which the model keeps itself sorted on further updates (because ofdynamicSortFilter
)?