You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更新QAbstractListModel时避免QSortFilterProxyModel自动执行过滤?

解决方案:让QSortFilterProxyModel仅手动触发过滤

要实现源模型更新时仅刷新视图显示,不自动执行过滤,仅在点击按钮时才应用过滤规则,核心是阻止QSortFilterProxyModel自动响应源模型的变更信号触发过滤,改为手动控制过滤时机。下面是具体实现步骤:

1. 自定义手动触发的代理模型

继承QSortFilterProxyModel,重写setSourceModel方法断开默认的自动过滤连接,并添加手动触发过滤的槽函数:

头文件(ManualSortFilterProxyModel.h)

#include <QSortFilterProxyModel>

class ManualSortFilterProxyModel : public QSortFilterProxyModel
{
    Q_OBJECT
public:
    explicit ManualSortFilterProxyModel(QObject *parent = nullptr);

    // 重写过滤规则,按你的需求实现(比如筛选selected == true)
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;

public slots:
    // 手动触发过滤的槽函数
    void triggerFilter();

protected:
    // 重写setSourceModel,断开自动触发过滤的信号连接
    void setSourceModel(QAbstractItemModel *sourceModel) override;
};

实现文件(ManualSortFilterProxyModel.cpp)

#include "ManualSortFilterProxyModel.h"
#include <QAbstractItemModel>

ManualSortFilterProxyModel::ManualSortFilterProxyModel(QObject *parent)
    : QSortFilterProxyModel(parent)
{}

bool ManualSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
    // 按你的需求实现过滤逻辑:仅保留selected为true的行
    // 这里假设selected是模型的第1列,根据你的实际模型结构调整索引
    QModelIndex index = sourceModel()->index(source_row, 1, source_parent);
    return sourceModel()->data(index).toBool();
}

void ManualSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    // 断开旧源模型的自动过滤信号连接(如果存在)
    if (QAbstractItemModel *oldSource = sourceModel()) {
        disconnect(oldSource, &QAbstractItemModel::dataChanged, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(oldSource, &QAbstractItemModel::rowsInserted, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(oldSource, &QAbstractItemModel::rowsRemoved, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(oldSource, &QAbstractItemModel::layoutChanged, this, &QSortFilterProxyModel::_q_sourceModelChanged);
    }

    // 调用父类方法设置新源模型
    QSortFilterProxyModel::setSourceModel(sourceModel);

    // 断开新源模型的自动过滤信号连接
    if (sourceModel) {
        disconnect(sourceModel, &QAbstractItemModel::dataChanged, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(sourceModel, &QAbstractItemModel::rowsInserted, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &QSortFilterProxyModel::_q_sourceModelChanged);
        disconnect(sourceModel, &QAbstractItemModel::layoutChanged, this, &QSortFilterProxyModel::_q_sourceModelChanged);
    }
}

void ManualSortFilterProxyModel::triggerFilter()
{
    // 手动触发过滤:重新计算所有行的过滤状态
    invalidateFilter();
}

2. 在主逻辑中使用自定义代理

  • 创建自定义代理实例,设置源模型到你的QAbstractListModel子类。
  • 将按钮的点击信号连接到代理的triggerFilter槽。
  • 视图(比如QListView)设置自定义代理为其模型。

示例代码:

#include "YourCustomListModel.h"
#include "ManualSortFilterProxyModel.h"
#include <QListView>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 创建源模型并添加测试数据
    YourCustomListModel sourceModel;
    // 这里假设你已经实现了添加数据的逻辑...

    // 创建自定义代理并关联源模型
    ManualSortFilterProxyModel proxyModel;
    proxyModel.setSourceModel(&sourceModel);

    // 创建视图和按钮
    QListView listView;
    listView.setModel(&proxyModel);

    QPushButton filterBtn("应用筛选");
    // 连接按钮点击事件到手动过滤槽
    QObject::connect(&filterBtn, &QPushButton::clicked, &proxyModel, &ManualSortFilterProxyModel::triggerFilter);

    // 布局UI
    QVBoxLayout layout;
    layout.addWidget(&listView);
    layout.addWidget(&filterBtn);

    QWidget window;
    window.setLayout(&layout);
    window.show();

    return app.exec();
}

3. 关键说明

  • 断开自动连接:通过在setSourceModel中断开源模型的dataChanged、rowsInserted等信号与代理内部_q_sourceModelChanged槽的连接,彻底阻止代理自动触发过滤。
  • 手动触发过滤:点击按钮时调用invalidateFilter(),这会让代理重新遍历所有源模型行,应用filterAcceptsRow的过滤规则,更新视图显示。
  • 视图正常更新:源模型的dataChanged信号仍会被代理转发到视图,所以当你修改元素的selected状态时,视图会立刻显示这个变更(比如取消选中的样式变化),直到点击按钮才会过滤掉不符合条件的行。

如果需要处理源模型的行插入/删除等场景,可以在合适的时机(比如行插入完成后)手动调用triggerFilter(),或者根据需求调整信号连接逻辑。

内容的提问来源于stack exchange,提问作者Adso4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 08:52:53