Adso4
Adso4

Reputation: 141

Update sourceModel() without applying filtering on QSortFilterProxyModel

I have a custom model (QAbstractListModel) and a custom proxy model (QSortFilterProxyModel) working as a filter. In the view, when I update the model, I need to execute "emit dataChanged(...)" in order to see this changes displayed.

But then, proxy model is automatically updated (filterAcceptsRow is called) and the view applies the corresponding filtering options.

I need to disable this behavior, to be able to update the view and only apply filtering when clicking a button, and not automatically.

For example:

With current behavior, this element disappears, since filter is applied when model changes. I want to display item with this change and apply filtering only when a button is clicked.

Upvotes: 2

Views: 1700

Answers (2)

Adso4
Adso4

Reputation: 141

Setting dynamic sort filter has worked for me. It was false by default in older versions of QT but I realized that it's true for current version!

Upvotes: 1

talamaki
talamaki

Reputation: 5482

You could implement a public method in your custom proxy model which you use for enabling/disabling the filter. In my example code I'm using Q_INVOKABLE macro to make enableFilter() callable from QML too. So you can enable the filter when a button is clicked by calling the method.

class ExampleFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
public:
    explicit ExampleFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}

    Q_INVOKABLE void setFilter(const QString & pattern) {
        QRegularExpression re(pattern, QRegularExpression::CaseInsensitiveOption);
        if (re.isValid()) {
            QSortFilterProxyModel::setFilterRegularExpression(pattern);
        }
        invalidateFilter();
    }

    Q_INVOKABLE void enableFilter(bool enabled) {
        m_enabled = enabled;
        invalidateFilter();
    }

protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override {
    if (m_enabled) {
        QModelIndex index = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
        QString str = sourceModel()->data(index, filterRole()).toString();
        return str.contains(filterRegularExpression());
    }
    return true;
}

private:
    bool m_enabled = false;
};

When you instantiate the model if you don't explicitly call enableFilter with true the filterAcceptsRow() method will return true for all rows.

myFilterProxyModel->setFilterRole(MyListModel::ExampleRole);
myFilterProxyModel->setFilter("^fullstringmatch$");
myFilterProxyModel->setSourceModel(myModel);
//myFilterProxyModel->enableFilter(true);

If you are using QML then you make the custom proxy model visible to the QML context e.g. by setting it as a context property (e.g. filterProxyModel) and enable the filter by calling

filterProxyModel.enableFilter(true)

Upvotes: 1

Related Questions