Qt之QTableView自定义排序/过滤(QSortFilterProxyModel实现,含源码+注释)

news2024/11/15 14:02:57

一、效果示例图

1.1 自定义表格排序示例图

本文过滤条件为行索引取余2等于0时返回true,且从下图中可以看到,奇偶行是各自挨在一起的。
在这里插入图片描述

1.2 自定义表格过滤示例图

下图添加两列条件(当前数据大于当前列条件才返回true,且多个列条件为且关系);下方添加条件分别为,”0列,条件值50“,”2列条件值40“,综合下来为0列值大于50且2列值大于40则返回true
在这里插入图片描述

二、相关理解

被动触发:不论是排序还是过滤,都会在添加数据的时候触发自定义排序/过滤函数;
主动触发:排序,可通过数据模型或过滤模型的sort函数触发;过滤,可通过setFilterRegExp函数触发。(此处说的两个函数主动调用后会运行自定义排序/过滤条件,前提是对应的函数有重写)

过滤:此外,除开本文写的filterAcceptsRow函数还有filterAcceptsColumn函数,其触发条件与filterAcceptsRow一致

三、源码

CMainWindow.h

#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H

#include "CSortFilterProxyModel.h"

#include <QMainWindow>
#include <QStandardItemModel>

namespace Ui {
class CMainWindow;
}

class CMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit CMainWindow(QWidget *parent = nullptr);
    ~CMainWindow();

private slots:
    /**
     * @brief on_btnCustom_clicked 自定义条件添加响应函数
     */
    void on_btnCustom_clicked();

    /**
     * @brief on_btnInitData_clicked 数据初始化响应函数
     */
    void on_btnInitData_clicked();

private:
    Ui::CMainWindow         *ui;

    QStandardItemModel      *m_model;               // 数据模型

    CSortFilterProxyModel   *m_customFilterModel;   // 自定义过滤器模型
};

#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"
#include "ui_CMainWindow.h"

#include <QMessageBox>

CMainWindow::CMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CMainWindow)
{
    ui->setupUi(this);

    // 数据模型对象创建
    m_model = new QStandardItemModel;

    // 自定义过滤器类对象创建
    m_customFilterModel = new CSortFilterProxyModel;
    // 设置数据源模型
    m_customFilterModel->setSourceModel(m_model);

    // 先将正常数据模型类设置到表格中
    ui->tableView->setModel(m_customFilterModel);

    // 设置表格可排序(设置过后通过自定义lessThan函数排序)
    ui->tableView->setSortingEnabled(true);
}

CMainWindow::~CMainWindow()
{
    // 释放内存空间
    delete m_customFilterModel;
    delete m_model;
    delete ui;
}

void CMainWindow::on_btnCustom_clicked()
{
    // 获取条件字符串
    QString colStr = ui->editCol->text();
    QString conditionStr = ui->editCondition->text();
    if(colStr.isEmpty() || conditionStr.isEmpty())
    {
        QMessageBox::information(this, "提示", "条件值为空,请输入条件");
        return;
    }
    // 获取条件并将其添加到自定义模型中
    m_customFilterModel->appendCondition(ui->editCol->text().toInt()
                                         , ui->editCondition->text().toInt());
    // 条件列和条件值编辑框清空
    ui->editCol->clear();
    ui->editCondition->clear();
    // 通过设置过滤条件触发自定义过滤(此处条件不会影响自定义过滤)
    m_customFilterModel->setFilterRegExp("");
}

void CMainWindow::on_btnInitData_clicked()
{
    // 虽然表格上是过滤模型,但是数据还是得设置到数据模型上才可
    for(int row = 0; row != 10; ++row)
    {
        for(int col = 0; col != 10; ++col)
        {
            // 设置当前行列的item, 并初始化随机值
            m_model->setItem(row, col, new QStandardItem(QString::number(rand() % 100)));
        }
    }
}

CMainWindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CMainWindow</class>
 <widget class="QMainWindow" name="CMainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>821</width>
    <height>525</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>CMainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="2" column="1">
     <widget class="QLineEdit" name="editCondition">
      <property name="text">
       <string/>
      </property>
      <property name="placeholderText">
       <string>条件值</string>
      </property>
     </widget>
    </item>
    <item row="2" column="0">
     <widget class="QLineEdit" name="editCol">
      <property name="text">
       <string/>
      </property>
      <property name="placeholderText">
       <string></string>
      </property>
     </widget>
    </item>
    <item row="4" column="0" colspan="3">
     <widget class="QTableView" name="tableView"/>
    </item>
    <item row="1" column="0">
     <widget class="QPushButton" name="btnInitData">
      <property name="text">
       <string>初始化数据</string>
      </property>
     </widget>
    </item>
    <item row="1" column="1">
     <widget class="QPushButton" name="btnCustom">
      <property name="text">
       <string>添加自定义模型条件</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>821</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

CSortFilterProxyModel.h

#ifndef CSORTFILTERPROXYMODEL_H
#define CSORTFILTERPROXYMODEL_H

#include <QSortFilterProxyModel>

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

    /**
     * @brief appendCondition 追加条件函数
     * @param col 条件列
     * @param val 条件值
     */
    void appendCondition(int col, int val);

    // QSortFilterProxyModel interface
protected:
    /**
     * @brief filterAcceptsRow 过滤行函数
     * @param source_row 当前行索引
     * @param source_parent 当前行父对象(没有则为空)
     * @return 过滤结果
     */
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;

    /**
     * @brief lessThan 排序函数
     * @param source_left 比较的左值
     * @param source_right 比较的右值
     * @return 比较结果
     */
    bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;

private:
    QMap<int, int>  m_mapFilterCondition;   // 条件值保存容器<列, 条件值>

};

#endif // CSORTFILTERPROXYMODEL_H

CSortFilterProxyModel.cpp

#include "CSortFilterProxyModel.h"

#include <QDebug>
#include <QStandardItemModel>

CSortFilterProxyModel::CSortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{

}

void CSortFilterProxyModel::appendCondition(int col, int val)
{
    // 直接赋值(不存在会添加,已存在会更新)
    m_mapFilterCondition[col] = val;
}

bool CSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
    // 定义返回值变量
    bool ret = true;
    // 获取数据源模型对象,并转换为需要的类型模板
    QStandardItemModel *srcModel = dynamic_cast<QStandardItemModel *>(sourceModel());
    if(nullptr != srcModel)
    {
        foreach(int col, m_mapFilterCondition.keys())
        {
            // 获取当前的item对象
            QStandardItem *item = srcModel->item(source_row, col);
            // 此时对应item不为空且整形值要小于条件值才显示
            if(nullptr != item && m_mapFilterCondition[col] > item->text().toInt())
            {
                ret = false;
                break;
            }
        }
    }
    return ret;
}

bool CSortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
    // 当前行为取余2等于0时返回true(就是说默认降序排序偶数行在前)
    return 0 == source_left.row() % 2;
}

总结

虽然自定义排序和过滤比较简单,但是在项目中非常实用,如需要将某行/列置顶,特殊条件过滤等。

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 o/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/377068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美团前端常见vue面试题(必备)

v-model 是如何实现的&#xff0c;语法糖实际是什么&#xff1f; &#xff08;1&#xff09;作用在表单元素上 动态绑定了 input 的 value 指向了 messgae 变量&#xff0c;并且在触发 input 事件的时候去动态把 message设置为目标值&#xff1a; <input v-model"sth…

Java程序设计基础学习笔记——类与对象、方法、递归、重载、可变参数、作用域、构造器、this

以下笔记整理自B站UP主韩顺平【零基础 快速学Java】韩顺平 零基础30天学会Java课程OOP面向对象程序设计(Object Oriented Programming)类就是数据类型&#xff0c;有属性和行为&#xff1b;对象是一个具体的实例从类到对象&#xff0c;目前有几种说法&#xff1a;创建一个对象实…

【网络安全入门】零基础小白必看!!!

看到很多小伙伴都想学习 网络安全 &#xff0c;让自己掌握更多的 技能&#xff0c;但是学习兴趣有了&#xff0c;却发现自己不知道哪里有 学习资源◇瞬间兴致全无&#xff01;◇ &#x1f604;在线找人要资料太卑微&#xff0c;自己上网下载又发现要收费0 &#x1f643;差点当…

HttpRunnerManager部署

基于HttpRunner的接口自动化测试平台: HttpRunner, djcelery and Django_. HttpRunner手册: http://cn.httprunner.org/git地址&#xff1a;httprunner/HttpRunnerManager: 基于 HttpRunner 的 Web 测试平台&#xff0c;已停止维护。 (github.com)部署机器&#xff1a;linux部署…

强强角逐,筑梦开源——2022年度启智社区优秀项目及开发者评选结果正式揭晓

2月24日&#xff0c;第四届OpenI/O启智开发者大会在深圳隆重开幕。本届大会以“算网筑基、开源启智、AI赋能”为主题&#xff0c;邀请国内人工智能开源领域领军院士亲自参加&#xff0c;汇聚学术界、产业界的技术专家&#xff0c;围绕中国算力网资源基座、开源社区服务支撑环境…

Tik Tok shop2023年度策略解读

一、TikTok Shop跨境电商数据显示自2022年上半年东南亚开放跨境电商入驻以来&#xff0c;全年GMV月均复合增速近90%&#xff1b;英国市场2022年下半年的平均交易客单价也同比2021年增长超40%&#xff1b;全年多个重要节点跨境GMV增长显著&#xff0c;例如2022年的圣诞季跨境GMV…

ESP32设备驱动-PCF8574IO扩展模块驱动

PCF8574IO扩展模块驱动 1、PCF8574介绍 PCF8574 是一个使用 I2C 协议的 8 位 I/O 端口扩展器。 通过开发板的SDA 和 SCL 引脚来控制多达 8 个数字 I/O 端口。 其中,A0,A1,A2 为地址引脚,P0,P1,P2,P3,P4,P5,P6,P7 为数字端口。PCF8574的地址如下: 在前面的文章,对PCF8574的…

【渐进交互学习网络:轻量级:超分:工业应用】

Progressive Interaction-Learning Network for Lightweight Single-Image Super-Resolution in Industrial Applications &#xff08;工业应用中轻量级单幅图像超分辨率渐进交互学习网络&#xff09; 近年来&#xff0c;基于深度学习&#xff08;DL&#xff09;的工业应用因…

大数据技术之Hive(四)分区表和分桶表、文件格式和压缩

一、分区表和分桶表1.1 分区表partitionhive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录&#xff0c;每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择式选择查询所需要的分区&#xff0c;这样的查询效率辉提高很多。1.1.1 分区表基本语…

Python 不同分辨率图像峰值信噪比[PSNR]

PNNR&#xff1a;全称为“Peak Signal-to-Noise Ratio”&#xff0c;中文直译为峰值信噪比 前言 一、定义 二、Python代码 1.自定义 2.Tensorflow 总结 前言 峰值信噪比是一种衡量图像质量的指标&#xff0c;描述的是最大值信号与北京噪音之间的关系。 一般来说&#xff0c;P…

Allegro如何删除铜皮上多余的空洞操作指导

Allegro如何删除铜皮上多余的空洞操作指导 在做PCB设计的时候,设计铜皮的时候是不希望铜皮上有多余的空洞的,设计完成前需要把多余的空洞删除,如下图 如何删除,具体操作如下 点击Shape点击Manual Void/Cavity

springboot中集成redis,二次封装成工具类

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;** 雄雄的小课堂 ** 现在是&#xff1a;2023年2月28日11:01:56 前言 redis大家应该都不陌生&#xff0c;我们在好多场景下都会使用&#xff0c;最近在面试别人的时候&#xff0c;也会问一些关于redis的…

华为OD机试题,用 Java 解【求符合要求的结对方式】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

博客系统--自动化测试

项目体验地址&#xff08;账号&#xff1a;123&#xff0c;密码&#xff1a;123&#xff09;http://120.53.20.213:8080/blog_system/login.html项目后端说明&#xff1a;http://t.csdn.cn/32Nnv项目码云Gitee地址&#xff1a;https://gitee.com/GoodManSS/project/tree/master…

【极狐 GitLab】在 web 端合并分支

一、概述 极狐GitLab是GitLab DevOps平台的中国发行版&#xff0c;一套完备的一站式DevOps平台&#xff0c;从根本上改变了开发、安全和运维团队协作和软件构建方式。极狐GitLab从构思到生产发布&#xff0c;帮助团队提高生产效率&#xff0c;将迭代周期从数周缩短至几分钟&am…

【Spring事物三千问】Spring的事务管理与MyBatis事物管理结合的原理

Spring的事务管理与MyBatis事物管理结合的原理前言正文原生的 MyBatis 的事务处理SqlSessionTransactionMyBatis 事务管理 与 Spring 事务管理的融合SpringManagedTransactionSqlSessionTemplateSqlSessionInterceptormybatis-spring 融合的原理连接获取 & 开启事务连接的关…

【Linux】理解进程地址空间

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 ​我们在学习C语言的时候&#xff0c;都学过内存区域的划分如栈、堆、代码区、数据区这些。但我们其实并不真正理解内存 — 我们之前一直说的内存是物理上的内存吗&#xff1f; 前言 我们…

18- TensorFlow实现CIFAR10分类 (tensorflow系列) (项目十八)

项目要点 导入cifar图片集: (train_image, train_label), (test_image, test_label) cifar.load_data() # cifar keras.datasets.cifar10图片归一化处理: train_image train_image / 255定义模型: model keras.Sequential() 输入层: model.add(layers.Conv2D(64, (3, 3…

HTML基础语法

一 前端简介构成语言说明结构HTML页面元素和内容表现CSS网页元素的外观和位置等页面样式&#xff08;美化&#xff09;行为JavaScript网页模型的定义和页面交互二 HTML1.简介HTML&#xff08;Hyper Text Markup Language&#xff09;&#xff1a;超文本标记语言。网页结构整体&…

Kubernetes05: Pod

Kubernetes05: Pod 1、概述 1&#xff09;最小部署的单元 2&#xff09;K8s不会处理容器&#xff0c;而是Pod&#xff0c;Pod里边包含多个容器&#xff08;一组容器的集合&#xff09; 3&#xff09;一个Pod中的容器共享一个网络命名空间 4) Pod是短暂存在的东西&#xff08;重…