QSortFilterProxyModel doesn't dynamically update filter?
Asked Answered
H

3

6

I have a custom subclass of QSortFilterProxyModel. I overrode filterAcceptsRow with the custom filter I wanted. Then I used it as such:

proxy = new MyFilterModel();
proxy->setSourceModel(...);
proxy->setDynamicSortFilter(true);
proxy->setFilterParams(...); // my custom function
comboBox->setModel(proxy);

However, when the underlying source model updated such that rows that previously were filtered should no longer be filtered, the combo box was not updated with those rows. Why is that?

Eventually I overrode setSourceModel in MyFilterModel like so:

void MyFilterModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    QSortFilterProxyModel::setSourceModel(sourceModel);

    connect(sourceModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(doInvalidateFilter()));
    connect(sourceModel, SIGNAL(modelReset()), this, SLOT(doInvalidateFilter()));

    invalidateFilter();
}

... where all doInvalidateFilter() does is call invalidateFilter. This worked - now when the model updated, the filter rows themselves also updated.

I figure that setDynamicSortFilter should have already taken care of this, though. Is this a bug in Qt?

Haynes answered 19/8, 2015 at 22:15 Comment(4)
Possible, you are not emitting dataChanged in your sorce model. I propose you to set dynamicSortFilter property to false and call invalidate() directly.Orgeat
@SaZ: I am, otherwise my fix wouldn't have worked (since I'm connecting the source model's dataChanged to the slot that invalidates the filter)Haynes
I can't reproduce this. Please post a self-contained test case - shove it all into a single, sweet and short main.cpp that has a single #include <QtWidgets> at the beginning, and #include "main.moc" at the end if you have any Q_OBJECT macros in the file.Topping
According to the Qt sources, the first thing QSortFilterProxyModel does on source data changed is verify the QModelIndex parameters denoting the span of change. This bit me. Ensure your dataChange is emit with valid indexes. If this doesn't work, try putting a breakpoint on QSortFilterProxyModelPrivate::_q_sourceDataChanged and step through to find the problem.Inclinometer
G
0

I had similar problem it occurred that proxy works fine. My model look something like:

class MyModel:public QAbstractListModel{
...
    bool setData(...) Q_DECL_OVERRIDE;
    MyItem* get(int index);
private:
    QList<MyItem*> m_model;
}

I thought I was changing MyItem (in QML) through a model (indirectly by calling "setData(...)"), but after I've bumped on your post I've check the QML file one more time and it occurred that I was changing not the model but item itself.

And model haven't know about changes so the proxy and the view.

I've updated MyItem to emit signals to the parent model if it has changed, so the model could emit DataChanged(...) and notify others.

May be you have something similar in your code?

Gottschalk answered 7/11, 2015 at 18:52 Comment(0)
C
0

Maybe this part of the documentation will be useful to you:

"Note that you should not update the source model through the proxy model when dynamicSortFilter is true. For instance, if you set the proxy model on a QComboBox, then using functions that update the model, e.g., addItem(), will not work as expected. An alternative is to set dynamicSortFilter to false and call sort() after adding items to the QComboBox."

Chantay answered 1/3, 2021 at 10:36 Comment(0)
R
0

I've bumped into exactly the same problem -- emit dataChanged() works as it should (content is updated) but the proxy model just wouldn't sort it.

@walkingTarget's comment however put me on the right track: not only dataChanged's QModelIndexes must be valid (there were in my case) but also sortColumn is taken into account!

Now you ask: "how do I set that column", right? This is how:

proxy->sort(column_to_sort);

i.e. first you must explicitly sort the model by yourself.

After this change I could remove all of my workarounds.

Richmound answered 6/11, 2021 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.