QSortFilterProxyModel的函数,信号介绍

前言

Qt版本:6.8.0

作用

  1. 动态数据排序
    通过setSortRole()指定排序依据的数据角色,调用sort()方法可实现:

    • 升序/降序排列
    • 多列联合排序
    • 自定义排序规则(需重写lessThan())
  2. 灵活数据过滤
    使用setFilterRegExp()设置过滤规则时:

    • 支持正则表达式匹配
    • 可指定过滤列(setFilterKeyColumn())
    • 允许动态修改过滤条件(实时更新视图)
  3. 数据视图映射
    创建数据展示层时:

    • 保持源数据完整性
    • 允许多个代理实例对应同一源模型
    • 支持数据转换显示(如日期格式处理)
// 示例:创建带过滤的代理模型
QSortFilterProxyModel *proxy = new QSortFilterProxyModel;
proxy->setSourceModel(sourceModel);  // 连接数据源
proxy->setFilterRegExp(QRegExp("^A", Qt::CaseInsensitive));  // 过滤首字母A项
proxy->setFilterKeyColumn(0);  // 对首列进行过滤

// 视图绑定代理模型
QTableView view;
view.setModel(proxy);

该模型在保持原始数据结构的同时,为视图层提供:

  • 独立的数据展示逻辑
  • 零拷贝的数据访问
  • 实时数据同步机制

与其他代理模型的对比

代理模型核心功能适用场景
QIdentityProxyModel保持结构不变,扩展或拦截数据/操作数据格式化、权限控制、监听
QSortFilterProxyModel动态排序和过滤数据表格排序、搜索过滤
QTransposeProxyModel转置行列(行变列,列变行)行列互换显示

API

父类APi

QAbstractProxyModel

virtual void setSourceModel(QAbstractItemModel *sourceModel) 设置\源模型给次代理模型
QAbstractItemModel * sourceModel() const 返回此代理模型设置的源模型

QModelIndex mapFromSource(const QModelIndex &sourceIndex) const

  • 作用:将源模型的索引 sourceIndex 转换为代理模型的索引。
  • 参数:sourceIndex 是源模型中的索引。
  • 返回值:代理模型中对应的索引。若 sourceIndex 已被代理模型过滤掉(不显示),返回无效索引。
  • 场景:当需要通过源模型的位置获取代理模型中的对应项(例如,在源模型数据更新后定位到代理视图中的对应位置)。

QModelIndex mapToSource(const QModelIndex &proxyIndex) const

  • 作用:将代理模型的索引 proxyIndex 转换为源模型的索引。

    参数:proxyIndex 是代理模型中的索引。

    返回值:源模型中对应的索引。若代理索引无效,返回无效索引。

    场景:当需要根据代理视图中的操作(如用户点击项)获取源模型的原始数据。

QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const

  • 作用:将源模型的选择区域 sourceSelection 转换为代理模型的选择区域。

    参数:sourceSelection 是源模型中的选择区域。

    返回值:代理模型中对应的选择区域。过滤掉的行/列会被排除。

    场景:当源模型数据变化后,需要同步更新代理视图中选中的项。

QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const

  • 作用:将代理模型的选择区域 proxySelection 转换为源模型的选择区域。

    参数:proxySelection 是代理模型中的选择区域。

    返回值:源模型中对应的选择区域。

    场景:当需要根据代理视图中的选中项操作源模型数据(如批量删除)。

带filter的函数用于过滤,带sort的函数用于排序

构造和析构函数

QSortFilterProxyModel(QObject *parent = nullptr)

  • 参数: parent - 父对象指针,默认为空
  • 返回值: 无
  • 作用: 创建一个 QSortFilterProxyModel对象,可以选择性地指定父对象

~QSortFilterProxyModel()

  • 参数: 无
  • 返回值: 无
  • 作用: 析构函数,销毁 QSortFilterProxyModel 对象

属性访问函数

bool autoAcceptChildRows() const

  • 参数: 无

    返回值: 布尔值,表示是否自动接受子行

    作用: 获取是否自动接受子行的设置状态

QBindable bindableAutoAcceptChildRows()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 autoAcceptChildRows 属性

    作用: 获取可绑定的 autoAcceptChildRows 属性

QBindable bindableDynamicSortFilter()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 dynamicSortFilter 属性

    作用: 获取可绑定的 dynamicSortFilter 属性

QBindableQt::CaseSensitivity bindableFilterCaseSensitivity()

  • 参数: 无

    返回值: QBindableQt::CaseSensitivity 对象,用于绑定 filterCaseSensitivity 属性

    作用: 获取可绑定的 filterCaseSensitivity 属性

QBindable bindableFilterKeyColumn()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 filterKeyColumn 属性

    作用: 获取可绑定的 filterKeyColumn 属性

QBindable bindableFilterRegularExpression()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 filterRegularExpression 属性

    作用: 获取可绑定的 filterRegularExpression 属性

QBindable bindableFilterRole()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 filterRole 属性

    作用: 获取可绑定的 filterRole 属性

QBindable bindableIsSortLocaleAware()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 isSortLocaleAware 属性

    作用: 获取可绑定的 isSortLocaleAware 属性

QBindable bindableRecursiveFilteringEnabled()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 recursiveFilteringEnabled 属性

    作用: 获取可绑定的 recursiveFilteringEnabled 属性

QBindableQt::CaseSensitivity bindableSortCaseSensitivity()

  • 参数: 无

    返回值: QBindableQt::CaseSensitivity 对象,用于绑定 sortCaseSensitivity 属性

    作用: 获取可绑定的 sortCaseSensitivity 属性

QBindable bindableSortRole()

  • 参数: 无

    返回值: QBindable 对象,用于绑定 sortRole 属性

    作用: 获取可绑定的 sortRole 属性

bool dynamicSortFilter() const

  • 参数: 无

    返回值: 布尔值,表示是否启用动态排序过滤

    作用: 获取动态排序过滤的设置状态

Qt::CaseSensitivity filterCaseSensitivity() const

  • 参数: 无

    返回值: Qt::CaseSensitivity 枚举值,表示过滤时的大小写敏感性

    作用: 获取过滤时的大小写敏感性设置

在这里插入图片描述

int filterKeyColumn() const

  • 参数: 无

    返回值: 整数,表示用于过滤的键列索引

    作用: 获取用于过滤的键列索引

QRegularExpression filterRegularExpression() const

  • 参数: 无

    返回值: QRegularExpression 对象,表示用于过滤的正则表达式

    作用: 获取用于过滤的正则表达式

int filterRole() const

  • 参数: 无

    返回值: 整数,表示用于过滤的数据角色

    作用: 获取用于过滤的数据角色

bool isRecursiveFilteringEnabled() const

  • 参数: 无

    返回值: 布尔值,表示是否启用递归过滤

    作用: 获取递归过滤的设置状态

bool isSortLocaleAware() const

  • 参数: 无

    返回值: 布尔值,表示排序时是否考虑本地化

    作用: 获取排序是否考虑本地化的设置状态

属性设置函数

void setAutoAcceptChildRows(bool accept)

  • 参数: accept - 是否自动接受子行

    返回值: 无

    作用: 设置是否自动接受子行

void setDynamicSortFilter(bool enable)

  • 参数: enable - 是否启用动态排序过滤

    返回值: 无

    作用: 设置是否启用动态排序过滤,数据变化时自动更新

// 切换动态更新
    QObject::connect(&dynamicCheckBox, &QCheckBox::toggled, [&](bool checked) {
        proxyModel.setDynamicSortFilter(checked); // 启用/禁用动态过滤
    });

void setFilterCaseSensitivity(Qt::CaseSensitivity cs)

  • 参数: cs - 过滤时的大小写敏感性

    返回值: 无

    作用: 设置过滤时的大小写敏感性

void setFilterKeyColumn(int column)

  • 参数: column - 用于过滤的键列索引

    返回值: 无

    作用: 设置用于过滤的键列索引,如果设置只有column列的数据被过滤

void setFilterRole(int role)

  • 参数: role - 用于过滤的数据角色

    返回值: 无

    作用: 指定过滤依据的角色(如 Qt::DisplayRole 或自定义角色)

void setRecursiveFilteringEnabled(bool recursive)

  • 参数: recursive - 是否启用递归过滤

    返回值: 无

    作用: 设置是否启用递归过滤

void setSortCaseSensitivity(Qt::CaseSensitivity cs)

  • 参数: cs - 排序时的大小写敏感性

    返回值: 无

    作用: 设置排序时的大小写敏感性

void setSortLocaleAware(bool on)

  • 参数: on - 排序时是否考虑本地化

    返回值: 无

    作用: 设置排序时是否考虑本地化

void setSortRole(int role)

  • 参数: role - 用于排序的数据角色

    返回值: 无

    作用: 设置用于排序的数据角色

排序状态查询函数

Qt::CaseSensitivity sortCaseSensitivity() const

  • 参数: 无

    返回值: Qt::CaseSensitivity 枚举值,表示排序时的大小写敏感性

    作用: 获取排序时的大小写敏感性

int sortColumn() const

  • 参数: 无

    返回值: 整数,表示用于排序的列索引

    作用: 获取当前用于排序的列索引

Qt::SortOrder sortOrder() const

  • 参数: 无

    返回值: Qt::SortOrder 枚举值,表示排序顺序

    作用: 获取当前排序顺序(升序或降序)

int sortRole() const

  • 参数: 无

    返回值: 整数,表示用于排序的数据角色

    作用: 获取用于排序的数据角色

重写的公共函数

QModelIndex buddy(const QModelIndex &index) const override
参数: index - 模型索引
返回值: QModelIndex,表示给定索引的伙伴索引
作用: 返回给定索引的伙伴索引

bool canFetchMore(const QModelIndex &parent) const override
参数: parent - 父索引
返回值: 布尔值,表示是否可以获取更多数据
作用: 判断给定父索引下是否可以获取更多数据

int columnCount(const QModelIndex &parent = QModelIndex()) const override
参数: parent - 父索引,默认为无效索引
返回值: 整数,表示列数
作用: 获取给定父索引下的列数

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
参数: index - 模型索引,role - 数据角色,默认为显示角色
返回值: QVariant,表示请求的数据
作用: 获取指定索引和角色的数据

bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
参数: data - MIME 数据,action - 拖放动作,row - 行,column - 列,parent - 父索引
返回值: 布尔值,表示拖放操作是否成功
作用: 处理拖放时的 MIME 数据

void fetchMore(const QModelIndex &parent) override
参数: parent - 父索引
返回值: 无
作用: 获取给定父索引下的更多数据

Qt::ItemFlags flags(const QModelIndex &index) const override
参数: index - 模型索引
返回值: Qt::ItemFlags,表示项目标志
作用: 获取指定索引的项目标志

bool hasChildren(const QModelIndex &parent = QModelIndex()) const override
参数: parent - 父索引,默认为无效索引
返回值: 布尔值,表示是否有子项
作用: 判断给定父索引是否有子项

QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
参数: section - 节索引,orientation - 方向,role - 数据角色,默认为显示角色
返回值: QVariant,表示请求的头数据
作用: 获取指定节、方向和角色的头数据

QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
参数: row - 行,column - 列,parent - 父索引,默认为无效索引
返回值: QModelIndex,表示请求的索引
作用: 获取指定行、列和父索引的模型索引

bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override
参数: column - 列起点,count - 列数,parent - 父索引,默认为无效索引
返回值: 布尔值,表示插入操作是否成功
作用: 在模型中插入列

bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override
参数: row - 行起点,count - 行数,parent - 父索引,默认为无效索引
返回值: 布尔值,表示插入操作是否成功
作用: 在模型中插入行

QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
参数: sourceIndex - 源模型索引
返回值: QModelIndex,表示代理模型索引
作用: 将源模型索引映射到代理模型索引

QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const override
参数: sourceSelection - 源选择
返回值: QItemSelection,表示代理选择
作用: 将源模型选择映射到代理模型选择

QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const override
参数: proxySelection - 代理选择
返回值: QItemSelection,表示源选择
作用: 将代理模型选择映射到源模型选择

QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
参数: proxyIndex - 代理模型索引
返回值: QModelIndex,表示源模型索引
作用: 将代理模型索引映射到源模型索引

QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const override
参数: start - 起始索引,role - 角色,value - 值,hits - 匹配数量(默认为1),flags - 匹配标志
返回值: QModelIndexList,表示匹配的索引列表
作用: 在模型中查找匹配项

QMimeData* mimeData(const QModelIndexList &indexes) const override
参数: indexes - 索引列表
返回值: QMimeData*,表示 MIME 数据
作用: 为指定索引创建 MIME 数据

QStringList mimeTypes() const override
参数: 无
返回值: QStringList,表示支持的 MIME 类型列表
作用: 获取模型支持的 MIME 类型

QModelIndex parent(const QModelIndex &child) const override
参数: child - 子索引
返回值: QModelIndex,表示父索引
作用: 获取指定子索引的父索引

bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override
参数: column - 列起点,count - 列数,parent - 父索引,默认为无效索引
返回值: 布尔值,表示删除操作是否成功
作用: 从模型中删除列

bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override
参数: row - 行起点,count - 行数,parent - 父索引,默认为无效索引
返回值: 布尔值,表示删除操作是否成功
作用: 从模型中删除行

int rowCount(const QModelIndex &parent = QModelIndex()) const override
参数: parent - 父索引,默认为无效索引
返回值: 整数,表示行数
作用: 获取给定父索引下的行数

bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
参数: index - 模型索引,value - 值,role - 角色,默认为编辑角色
返回值: 布尔值,表示设置操作是否成功
作用: 设置指定索引和角色的数据

bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override
参数: section - 节索引,orientation - 方向,value - 值,role - 角色,默认为编辑角色
返回值: 布尔值,表示设置操作是否成功
作用: 设置指定节、方向和角色的头数据

void setSourceModel(QAbstractItemModel *sourceModel) override
参数: sourceModel - 源模型指针
返回值: 无
作用: 设置代理模型的源模型

QModelIndex sibling(int row, int column, const QModelIndex &idx) const override
参数: row - 行,column - 列,idx - 模型索引
返回值: QModelIndex,表示兄弟索引
作用: 获取指定索引的兄弟索引

void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
参数: column - 列,order - 排序顺序,默认为升序
返回值: 无
作用: 按指定列和顺序对模型进行排序

QSize span(const QModelIndex &index) const override
参数: index - 模型索引
返回值: QSize,表示跨度大小
作用: 获取指定索引的跨度大小

Qt::DropActions supportedDropActions() const override
参数: 无
返回值: Qt::DropActions,表示支持的拖放动作
作用: 获取模型支持的拖放动作

公共槽函数

void invalidate()

  • 参数: 无

    返回值: 无

    作用: 使代理模型的内部状态无效,强制重新评估所有项目

void setFilterFixedString(const QString &pattern)

  • 参数: pattern - 固定字符串模式

    返回值: 无

    作用: 设置固定字符串过滤器模式,不符合过滤条件的被省略

model->setStringList(QStringList({
    "C++",
    "Java",
    "Python",
    "C#",
    "JavaScript",
    "Ruby",
    "Swift",
    "Kotlin",
    "Go",
    "Rust",
    "PHP",
    "TypeScript",
    "Dart",
    "Perl",
    "Haskell"
    }));
    proxyModel->setSourceModel(model);
    proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); // 不区分大小写
    proxyModel->setFilterFixedString("C"); // 直接设置过滤字符串
    ui->listView->setModel(proxyModel);

在这里插入图片描述

void setFilterRegularExpression(const QString &pattern)

  • 参数: pattern - 正则表达式模式字符串

    返回值: 无

    作用: 从字符串设置正则表达式过滤器模式

// 6. 信号槽连接:动态调整过滤规则
    QObject::connect(&filterEdit, &QLineEdit::textChanged, [&](const QString &text) {
        if (useRegexCheckBox.isChecked()) {
            proxyModel.setFilterRegularExpression(text);
        } else {
            proxyModel.setFilterWildcard(text); // 通配符过滤(如 "A*")
        }
    });

void setFilterRegularExpression(const QRegularExpression &regularExpression)

  • 参数: regularExpression - 正则表达式对象

    返回值: 无

    作用: 设置正则表达式过滤器模式,和上面的没区别直接用上面的即可

void setFilterWildcard(const QString &pattern)

  • 参数: pattern - 通配符模式

    返回值: 无

    作用: 设置通配符过滤器模式

// 6. 信号槽连接:动态调整过滤规则
    QObject::connect(&filterEdit, &QLineEdit::textChanged, [&](const QString &text) {
        if (useRegexCheckBox.isChecked()) {
            proxyModel.setFilterRegularExpression(text);
        } else {
            proxyModel.setFilterWildcard(text); // 通配符过滤(如 "A*")
        }
    });

信号

void autoAcceptChildRowsChanged(bool autoAcceptChildRows)

  • 参数: autoAcceptChildRows - 新的自动接受子行状态

    作用: 当自动接受子行的设置改变时发出

void filterCaseSensitivityChanged(Qt::CaseSensitivity filterCaseSensitivity)

  • 参数: filterCaseSensitivity - 新的过滤大小写敏感性

    作用: 当过滤大小写敏感性改变时发出

void filterRoleChanged(int filterRole)

  • 参数: filterRole - 新的过滤角色

    作用: 当过滤角色改变时发出

void recursiveFilteringEnabledChanged(bool recursiveFilteringEnabled)

  • 参数: recursiveFilteringEnabled - 新的递归过滤状态

    作用: 当递归过滤设置改变时发出

void sortCaseSensitivityChanged(Qt::CaseSensitivity sortCaseSensitivity)

  • 参数: sortCaseSensitivity - 新的排序大小写敏感性

    作用: 当排序大小写敏感性改变时发出

void sortLocaleAwareChanged(bool sortLocaleAware)

  • 参数: sortLocaleAware - 新的排序本地化感知状态

    作用: 当排序本地化感知设置改变时发出

void sortRoleChanged(int sortRole)

  • 参数: sortRole - 新的排序角色

    作用: 当排序角色改变时发出

保护函数

void beginFilterChange()

  • 参数: 无

    返回值: 无

    作用: 开始过滤器更改,通知模型过滤器即将更改

bool filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const

  • 参数: source_column - 源列索引,source_parent - 源父索引

    返回值: 布尔值,表示是否接受该列

    作用: 判断是否接受源模型中的指定列

bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const

  • 参数: source_row - 源行索引,source_parent - 源父索引

    返回值: 布尔值,表示是否接受该行

    作用: 判断是否接受源模型中的指定行

void invalidateColumnsFilter()

  • 参数: 无

    返回值: 无

    作用: 使列过滤器无效,强制重新评估所有列

void invalidateFilter()

  • 参数: 无

    返回值: 无

    作用: 使过滤器无效,强制重新评估所有过滤条件

void invalidateRowsFilter()

  • 参数: 无

    返回值: 无

    作用: 使行过滤器无效,强制重新评估所有行

bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const

  • 参数: source_left - 左侧源索引,source_right - 右侧源索引

    返回值: 布尔值,表示左侧是否小于右侧

    作用: 比较两个源模型索引的大小关系,用于排序

bind函数的用法

QSortFilterProxyModel中的bindable函数是Qt 6引入的新特性,它们提供了属性绑定系统的支持。

Bindable函数基本概念

Qt 6中引入的属性绑定系统允许你创建属性之间的动态关系,当一个属性变化时,所有绑定到它的属性都会自动更新。

主要的bindable函数包括:

QBindable<bool> bindableAutoAcceptChildRows()
QBindable<bool> bindableDynamicSortFilter()
QBindable<Qt::CaseSensitivity> bindableFilterCaseSensitivity()
QBindable<int> bindableFilterKeyColumn()
QBindable<QRegularExpression> bindableFilterRegularExpression()
QBindable<int> bindableFilterRole()
QBindable<bool> bindableIsSortLocaleAware()
QBindable<bool> bindableRecursiveFilteringEnabled()
QBindable<Qt::CaseSensitivity> bindableSortCaseSensitivity()
QBindable<int> bindableSortRole()

基本用法示例

1. 单向绑定(从源到目标)

将一个属性绑定到另一个属性,使目标属性随源属性变化而自动更新:

QSortFilterProxyModel *proxyModel1 = new QSortFilterProxyModel(this);
QSortFilterProxyModel *proxyModel2 = new QSortFilterProxyModel(this);

// 将proxyModel2的过滤列绑定到proxyModel1的过滤列
QBindable<int> bindable1 = proxyModel1->bindableFilterKeyColumn();
QBindable<int> bindable2 = proxyModel2->bindableFilterKeyColumn();

bindable2.setBinding([&bindable1]() { return bindable1.value(); });

// 现在当proxyModel1的过滤列改变时,proxyModel2的过滤列会自动更新
proxyModel1->setFilterKeyColumn(2); // proxyModel2的过滤列也会变为2

2. 双向绑定

使两个属性保持同步,任一属性变化都会影响另一个:

// 创建两个代理模型
QSortFilterProxyModel *proxyModel1 = new QSortFilterProxyModel(this);
QSortFilterProxyModel *proxyModel2 = new QSortFilterProxyModel(this);

// 获取bindable对象
auto bindable1 = proxyModel1->bindableDynamicSortFilter();
auto bindable2 = proxyModel2->bindableDynamicSortFilter();

// 创建双向绑定
QProperty<bool> sharedProperty(true);
bindable1.setBinding([&sharedProperty]() { return sharedProperty.value(); });
bindable2.setBinding([&sharedProperty]() { return sharedProperty.value(); });

// 使用共享属性更新两个模型
sharedProperty = false; // 两个模型的dynamicSortFilter都会变为false

3. 条件绑定

基于条件创建复杂的绑定关系:

QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
QCheckBox *caseSensitiveCheckBox = new QCheckBox("区分大小写", this);
QCheckBox *localeSensitiveCheckBox = new QCheckBox("区分本地语言", this);

// 将过滤和排序的大小写敏感性绑定到复选框
QProperty<bool> caseSensitiveProperty;
caseSensitiveProperty.setBinding([caseSensitiveCheckBox]() { 
    return caseSensitiveCheckBox->isChecked(); 
});

// 过滤大小写敏感性绑定
proxyModel->bindableFilterCaseSensitivity().setBinding([&caseSensitiveProperty]() {
    return caseSensitiveProperty.value() ? Qt::CaseSensitive : Qt::CaseInsensitive;
});

// 排序大小写敏感性绑定
proxyModel->bindableSortCaseSensitivity().setBinding([&caseSensitiveProperty]() {
    return caseSensitiveProperty.value() ? Qt::CaseSensitive : Qt::CaseInsensitive;
});

// 本地语言感知绑定
proxyModel->bindableIsSortLocaleAware().setBinding([localeSensitiveCheckBox]() {
    return localeSensitiveCheckBox->isChecked();
});

4. 组合多个属性

将多个属性组合到单个绑定中:

QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
QLineEdit *searchBox = new QLineEdit(this);
QComboBox *columnComboBox = new QComboBox(this);
columnComboBox->addItems({"姓名", "年龄", "年级", "所有列"});

// 根据组合框选择的列设置过滤列
proxyModel->bindableFilterKeyColumn().setBinding([columnComboBox]() {
    int index = columnComboBox->currentIndex();
    return (index == 3) ? -1 : index; // -1表示所有列
});

// 设置过滤表达式绑定到搜索框
QProperty<QString> searchTextProperty;
searchTextProperty.setBinding([searchBox]() { return searchBox->text(); });

proxyModel->bindableFilterRegularExpression().setBinding([&searchTextProperty]() {
    return QRegularExpression(searchTextProperty.value(), 
                             QRegularExpression::CaseInsensitiveOption);
});

5. 绑定到自定义UI组件

将过滤条件绑定到自定义UI控件:

QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
QSlider *minAgeSlider = new QSlider(Qt::Horizontal, this);
QSlider *maxAgeSlider = new QSlider(Qt::Horizontal, this);
minAgeSlider->setRange(0, 100);
maxAgeSlider->setRange(0, 100);
maxAgeSlider->setValue(100);

// 创建自定义过滤模型
class AgeFilterProxyModel : public QSortFilterProxyModel {
public:
    QProperty<int> minAge{0};
    QProperty<int> maxAge{100};
    
protected:
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override {
        if (!QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent))
            return false;
            
        QModelIndex ageIndex = sourceModel()->index(source_row, 1, source_parent);
        int age = sourceModel()->data(ageIndex).toInt();
        return age >= minAge && age <= maxAge;
    }
};

// 使用自定义模型
AgeFilterProxyModel *ageProxyModel = new AgeFilterProxyModel(this);
ageProxyModel->setSourceModel(studentModel);

// 绑定滑块到过滤条件
QProperty<int> minAgeProperty;
QProperty<int> maxAgeProperty;

minAgeProperty.setBinding([minAgeSlider]() { return minAgeSlider->value(); });
maxAgeProperty.setBinding([maxAgeSlider]() { return maxAgeSlider->value(); });

// 将自定义属性与过滤器绑定
ageProxyModel->minAge.setBinding([&minAgeProperty]() { return minAgeProperty.value(); });
ageProxyModel->maxAge.setBinding([&maxAgeProperty]() { return maxAgeProperty.value(); });

// 当滑块值变化时,invalidateFilter以重新应用过滤器
connect(minAgeSlider, &QSlider::valueChanged, ageProxyModel, &QSortFilterProxyModel::invalidateFilter);
connect(maxAgeSlider, &QSlider::valueChanged, ageProxyModel, &QSortFilterProxyModel::invalidateFilter);

高级用法

1. 多代理模型链

创建多个代理模型链,每个处理不同的过滤或排序功能:

// 基础学生模型
StudentTableModel *studentModel = new StudentTableModel(this);

// 名字过滤代理
QSortFilterProxyModel *nameFilterProxy = new QSortFilterProxyModel(this);
nameFilterProxy->setSourceModel(studentModel);
nameFilterProxy->setFilterKeyColumn(0); // 姓名列

// 年龄过滤代理(链在名字过滤代理后)
AgeFilterProxyModel *ageFilterProxy = new AgeFilterProxyModel(this);
ageFilterProxy->setSourceModel(nameFilterProxy);

// 排序代理(最终代理,连接到视图)
QSortFilterProxyModel *sortProxy = new QSortFilterProxyModel(this);
sortProxy->setSourceModel(ageFilterProxy);
sortProxy->setSortRole(Qt::DisplayRole);

// 连接到视图
tableView->setModel(sortProxy);

// 绑定UI控件
QLineEdit *nameSearch = new QLineEdit(this);
nameFilterProxy->bindableFilterRegularExpression().setBinding([nameSearch]() {
    return QRegularExpression(nameSearch->text(), QRegularExpression::CaseInsensitiveOption);
});

2. 响应式界面与属性绑定

创建响应式UI,其中多个UI元素相互关联:

QCheckBox *enableFilterCheckBox = new QCheckBox("启用过滤", this);
QLineEdit *searchBox = new QLineEdit(this);
searchBox->setEnabled(false);

// 使搜索框状态绑定到复选框
QProperty<bool> filterEnabledProperty;
filterEnabledProperty.setBinding([enableFilterCheckBox]() {
    return enableFilterCheckBox->isChecked();
});

// UI响应性
QObject::connect(&filterEnabledProperty, &QProperty<bool>::valueChanged, 
                 searchBox, &QLineEdit::setEnabled);

// 模型过滤响应性
proxyModel->bindableFilterRegularExpression().setBinding([&filterEnabledProperty, searchBox]() {
    if (!filterEnabledProperty.value())
        return QRegularExpression(); // 空表达式不过滤
    else
        return QRegularExpression(searchBox->text(), QRegularExpression::CaseInsensitiveOption);
});

注意事项和最佳实践

  1. 性能考虑:属性绑定很强大,但过度使用可能导致性能问题,特别是在复杂绑定链中。

  2. 避免循环绑定:确保不会创建循环依赖,例如A绑定到B,B绑定到C,C又绑定回A。

  3. 绑定优先级:当使用setBinding()时,它会覆盖任何先前的绑定或手动设置的值。确保按正确的顺序设置绑定。

  4. 显式更新:虽然绑定会自动传播更改,但有时可能需要调用invalidateFilter()来确保视图更新。

  5. Qt 6特性:这些bindable函数仅在Qt 6中可用,如果你的项目需要兼容Qt 5,则不能使用此功能。

性能考虑

对于大型数据集,QSortFilterProxyModel的一些重要性能考虑:

动态过滤:
setDynamicSortFilter(true)会导致每次数据变化时重新排序和过滤
对于频繁更新的大型数据集,可以临时禁用:

   proxyModel->setDynamicSortFilter(false);
   // 进行批量更新
   proxyModel->setDynamicSortFilter(true);

延迟过滤:
对于搜索框实时过滤,可以使用定时器延迟应用过滤器:

   QTimer *filterTimer = new QTimer(this);
   filterTimer->setSingleShot(true);
   connect(searchBox, &QLineEdit::textChanged, [=]() {
       filterTimer->start(300); // 300ms延迟
   });
   connect(filterTimer, &QTimer::timeout, [=]() {
       proxyModel->setFilterRegularExpression(searchBox->text());
   });

过滤

在Qt中,QSortFilterProxyModel 用于对数据模型进行过滤和排序。若要对列表模型(如 QAbstractListModelQStringListModel)进行过滤,需通过子类化或直接配置代理模型实现。

1. 基本过滤原理

通过重写 filterAcceptsRow() 方法,决定哪些行(对于列表模型即每个项)应被保留。该方法返回 true 表示保留该行,false 表示过滤掉。


2. 实现过滤的步骤

(1) 子类化 QSortFilterProxyModel
class MyFilterProxyModel : public QSortFilterProxyModel {
public:
    // 可选:设置过滤条件(如关键字)
    void setFilterKeyword(const QString &keyword) {
        m_keyword = keyword;
        invalidateFilter(); // 触发重新过滤
    }

protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override {
        QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
        QString data = sourceModel()->data(index, Qt::DisplayRole).toString(); // 获取显示数据
        return data.contains(m_keyword, Qt::CaseInsensitive); // 示例:模糊匹配
    }

private:
    QString m_keyword;
};
(2) 应用代理模型
// 创建源模型(示例为字符串列表模型)
QStringListModel *sourceModel = new QStringListModel;
sourceModel->setStringList({"Apple", "Banana", "Cherry", "Grape"});

// 创建代理模型并设置源模型
MyFilterProxyModel *proxyModel = new MyFilterProxyModel;
proxyModel->setSourceModel(sourceModel);

// 设置过滤关键字
proxyModel->setFilterKeyword("ap"); // 匹配 "Apple" 和 "Grape"

// 将代理模型设置到视图(如 QListView)
QListView *listView = new QListView;
listView->setModel(proxyModel);

3. 动态过滤

若需动态更新过滤条件(如根据用户输入),调用 invalidateFilter()-保护函数 强制代理模型重新计算过滤结果。

// 示例:当用户输入文本时更新过滤
QLineEdit *searchBox = new QLineEdit;
connect(searchBox, &QLineEdit::textChanged, proxyModel, &MyFilterProxyModel::setFilterKeyword);

4. 使用内置过滤方法

无需子类化时,可直接通过 setFilterFixedString() 或正则表达式过滤:

QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel;
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); // 不区分大小写
proxyModel->setFilterFixedString("ap"); // 直接设置过滤字符串

5. 处理复杂过滤逻辑

若需基于自定义角色或复杂条件过滤,可在 filterAcceptsRow 中访问模型数据的不同角色:

bool filterAcceptsRow(int sourceRow, const QModelIndex&) const override {
    QModelIndex index = sourceModel()->index(sourceRow, 0);
    int role = Qt::UserRole + 1; // 假设自定义角色
    QString data = sourceModel()->data(index, role).toString();
    return data.startsWith("A");
}

注意事项

  • 性能:频繁调用 invalidateFilter() 可能影响性能,建议对大量数据使用异步处理或延迟过滤。
  • 正则表达式:通过 setFilterRegularExpression() 支持更复杂的模式匹配。
  • 多列模型:若源模型是多列(如表格),需结合 filterAcceptsColumn() 处理。

排序

在 Qt 中,QSortFilterProxyModel 不仅可以过滤数据,还能对数据进行动态排序。

1. 基本排序原理

QSortFilterProxyModel 默认支持通过调用 sort() 方法对数据进行排序。排序依据可以是数据模型的默认角色(如 Qt::DisplayRole)或自定义角色。排序逻辑可以通过以下两种方式控制:

  1. 默认排序:直接使用 sort() 方法,基于 DisplayRole 或指定的角色按字符串或数值排序。
  2. 自定义排序:子类化 QSortFilterProxyModel 并重写 lessThan() 方法,实现复杂的排序逻辑。

2. 实现排序的步骤

(1) 基本排序示例

以下代码演示如何对 QStringListModel 进行升序/降序排序:

#include <QApplication>
#include <QStringListModel>
#include <QSortFilterProxyModel>
#include <QListView>
#include <QPushButton>

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

    // 1. 创建源模型(字符串列表)
    QStringList data = {"Banana", "apple", "Cherry", "Grape"};
    QStringListModel sourceModel;
    sourceModel.setStringList(data);

    // 2. 创建代理模型并绑定源模型
    QSortFilterProxyModel proxyModel;
    proxyModel.setSourceModel(&sourceModel);

    // 3. 设置排序参数
    proxyModel.setSortCaseSensitivity(Qt::CaseInsensitive); // 不区分大小写
    proxyModel.setSortRole(Qt::DisplayRole);                // 按显示文本排序

    // 4. 创建视图和排序按钮
    QListView listView;
    listView.setModel(&proxyModel); // 视图绑定代理模型

    QPushButton sortAscButton("Sort Ascending");
    QPushButton sortDescButton("Sort Descending");

    // 5. 点击按钮触发排序
    QObject::connect(&sortAscButton, &QPushButton::clicked, [&]() {
        proxyModel.sort(0, Qt::AscendingOrder); // 按升序排序列 0
    });

    QObject::connect(&sortDescButton, &QPushButton::clicked, [&]() {
        proxyModel.sort(0, Qt::DescendingOrder); // 按降序排序列 0
    });

    // 6. 布局
    QWidget window;
    QVBoxLayout layout(&window);
    layout.addWidget(&listView);
    layout.addWidget(&sortAscButton);
    layout.addWidget(&sortDescButton);
    window.show();

    return app.exec();
}

运行效果

  • 点击 “Sort Ascending” 按钮,列表按字母升序排列(不区分大小写):apple, Banana, Cherry, Grape
  • 点击 “Sort Descending” 按钮,列表按字母降序排列:Grape, Cherry, Banana, apple

3. 动态排序

启用 setDynamicSortFilter(true) 后,当源模型数据变化时,代理模型会自动重新排序。例如,在数据中添加新项时,列表会自动按当前排序规则更新。

proxyModel.setDynamicSortFilter(true); // 启用动态排序

// 添加新项测试动态排序
sourceModel.setStringList(data << "Apricot"); 
// 视图会自动更新并按当前顺序排列

4. 自定义排序逻辑

如果需要更复杂的排序规则(如按字符串长度排序),可以子类化 QSortFilterProxyModel 并重写 lessThan() 方法。

示例:按字符串长度排序
class LengthSortProxyModel : public QSortFilterProxyModel {
protected:
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override {
        // 获取左右项的字符串长度
        int leftLength = sourceModel()->data(left, Qt::DisplayRole).toString().length();
        int rightLength = sourceModel()->data(right, Qt::DisplayRole).toString().length();
        return leftLength < rightLength; // 按长度升序
    }
};

// 使用自定义代理模型
LengthSortProxyModel proxyModel;
proxyModel.setSourceModel(&sourceModel);
proxyModel.sort(0, Qt::AscendingOrder); // 按长度升序

结果

  • 按字符串长度排序:Grape (5), apple (5), Banana (6), Cherry (6), Apricot (7)

5. 结合过滤与排序

QSortFilterProxyModel 可以同时启用过滤和排序功能。代理模型会先过滤数据,再对过滤后的结果进行排序。

// 设置过滤规则
proxyModel.setFilterRegularExpression("a"); // 过滤包含字母 "a" 的项

// 设置排序规则
proxyModel.sort(0, Qt::AscendingOrder);

结果

  • 过滤后数据:Banana, apple, Grape, Apricot
  • 排序后结果:apple, Apricot, Banana, Grape

6. 关键函数说明

  1. sort(int column, Qt::SortOrder order)

    • 对指定列(列表模型为 0)按升序(Qt::AscendingOrder)或降序(Qt::DescendingOrder)排序。
    • 直接调用时会立即触发排序。
  2. setSortRole(int role)

    • 指定排序依据的角色,例如 Qt::DisplayRole(默认)或自定义角色(如 Qt::UserRole 存储的数值)。
  3. setSortCaseSensitivity(Qt::CaseSensitivity cs)

    • 控制排序时是否区分大小写(默认区分)。
  4. setDynamicSortFilter(bool enable)

    • 启用后,源模型数据变化时自动重新排序。

7. 通过视图交互排序

如果视图支持点击列头排序(如 QTableView),可直接通过视图触发排序。但对于列表模型(QListView),通常需要手动按钮或代码控制。


注意事项

  • 性能:对大型数据集频繁排序可能导致卡顿,建议异步处理或分页。
  • 自定义模型:如果源模型的数据角色需要特殊处理(如数值排序),需确保数据角色正确实现。
  • 多列排序QSortFilterProxyModel 不支持多列联合排序,需自定义逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值