一、效果示例图
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/)
注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除