[Qt]自定义表头实现过滤功能

1. 写在前面

过滤功能源自项目上交互优化用户体验,在表头添加过滤符号实现过滤,替换以往在表格上方占用一行过滤项进行过滤。

2. 过滤提示

过滤提示就是三态图标(normal,hover,press)。这三种状态的实现通过鼠标移动事件和鼠标点击事件来实现。具体实现如下:

1)hover状态在鼠标移动事件中实现

void CFilterHeaderView::mouseMoveEvent(QMouseEvent *e)
{
    m_hover = logicalIndexAt(e->pos());
    if (m_hover != -1)
        updateSection(m_hover);
    QHeaderView::mouseMoveEvent(e);
}

bool CFilterHeaderView::event(QEvent *e)
{
    switch(e->type())
    {
    case QEvent::Leave:
    case QEvent::HoverLeave:
        if (m_hover != -1)
            updateSection(m_hover);
        m_hover = -1;
        break;
    default:
        break;
    }
    return QHeaderView::event(e);
}

如果悬浮在某一列上,hover值等于该列的index,否则等于-1。如果hover值不等于-1,则刷新该列(updateSection)。

mouseMoveEvent中检测鼠标悬浮在那个表格列上。event函数中监听Leave和HoverLeave事件。

2)press状态在鼠标点击事件中实现

void CFilterHeaderView::mousePressEvent(QMouseEvent *e)
{
    m_press = logicalIndexAt(e->pos());
    if (m_press != -1)
        updateSection(m_press);
    QHeaderView::mousePressEvent(e);
}

void CFilterHeaderView::mouseReleaseEvent(QMouseEvent *e)
{
    m_press = -1;
    QHeaderView::mouseReleaseEvent(e);
}

press的实现较为简单,鼠标点击更新press,鼠标释放press置为-1。

3)过滤提示的实现。

过滤提示在paintSection函数中实现,首先是调用基类paintSection实现表头的绘制,然后是检测有没有定义过滤角色。如果有定义过滤角色,则根据三态选择对应的图标,绘制位置默认水平靠右垂直居住,也可以自己指定位置。最后是绘制过滤提示。具体实现如下:

void CFilterHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();

    QVariant filterVar = model()->headerData(logicalIndex, orientation(), FilterRole);
    if (filterVar.isValid() && filterVar.toBool())
    {
        QPixmap pix = m_norFilterPix;
        bool b_contain = getFilterRect(rect).contains(cursor().pos());
        if (logicalIndex == m_hover && b_contain)
        {
            pix = m_hovFilterPix;
        }
        if (logicalIndex == m_press && b_contain)
        {
            pix = m_preFilterPix;
        }

        int align = Qt::AlignRight | Qt::AlignVCenter;
        QVariant alignVar = model()->headerData(logicalIndex, orientation(), FilterAlignmentRole);
        if (alignVar.isValid())
        {
            align = alignVar.toInt();
        }
        style()->drawItemPixmap(painter, rect, align, pix);
    }
}

表格绘制的区域和过滤提示绘制的区域不一致,要根据过滤图标大小进行计算过滤提示的区域。只有当鼠标在过滤区域位置上方,hover和press才有效,否则仍然是normal状态。过滤区域绘制的位置可以从外面获取,也可以使用默认位置。最后style()->drawItemPixmap进行绘制。

调用基类paintSection方法前后调用QPainter::save()和QPainter::restore()是必要的。如果不调用,style()->drawItemPixmap是不会起作用的。

4)过滤提示点击信号

点击过滤提示会发出信号,连接此信号可以进行过滤功能的实现。具体实现如下:

void CFilterHeaderView::mouseReleaseEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton)
    {
        int section = logicalIndexAt(e->pos());
        QVariant filterVar = model()->headerData(section, orientation(), FilterRole);
        if (filterVar.isValid() && filterVar.toBool())
        {
            QRect rect(sectionViewportPosition(section), 0, sectionSize(section), height());
            if (getFilterRect(rect).contains(cursor().pos()))
            {
                emit filterClicked(section);
            }
        }
    }
    QHeaderView::mouseReleaseEvent(e);
}

过滤信号发出的条件:1. 左键点击,2. 定义了过滤功能,3. 鼠标在过滤提示区域中

3. 使用过滤功能

使用过滤表头的方法如下:

    m_tableView = new QTableView(this);
    m_model = new QStandardItemModel(this);
    m_filterModel = new QSortFilterProxyModel(this);
    m_filterModel->setSourceModel(m_model);
    m_filterModel->setSortRole(Qt::ToolTipRole);
    m_tableView->setModel(m_filterModel);

    QHBoxLayout* mainLayout = new QHBoxLayout(this);
    mainLayout->setMargin(0);
    mainLayout->addWidget(m_tableView);
    setLayout(mainLayout);

    m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);

    m_tableView->verticalHeader()->hide();
    CFilterHeaderView* pHeader = new CFilterHeaderView(this);
    connect(pHeader, &CFilterHeaderView::filterClicked, this, &Widget::onFilterClicked);
    m_tableView->setHorizontalHeader(pHeader);

使用过滤表头和使用普通表头没有太大的差别。这里过滤功能有QSortFilterProxyModel实现,水平表头替换成自定义的CFilterHeaderView。

4. 写在最后

实现过滤表头的原理如上所诉。具体完整的项目路径参考如下地址:

https://github.com/zhugp125/QtDemo/tree/master/FilterHeaderView

原文地址:https://www.cnblogs.com/zhugaopeng/p/11146809.html

时间: 2024-11-05 12:26:09

[Qt]自定义表头实现过滤功能的相关文章

Qt调用dll中的功能函数

DLL 优点 ------------------------------------- 1.扩展了应用程序的特性: 2.可以用许多种编程语言来编写: 3.简化了软件项目的管理: 4.有助于节省内存: 5.有助于资源共享: 6.有助于应用程序的本地化: 7.有助于解决平台差异: 8.可以用于一些特殊的目的.windows使得某些特性只能为DLL所用. 转载:http://www.cnblogs.com/hicjiajia/archive/2010/08/27/1810239.html Qt调用d

iRSF快速简单易用的实现列表、排序、过滤功能

IRSF 是由javascript编写,iRSF快速简单易用的实现列表.排序.过滤功能(该三种操作以下简称为 RSF ). iRSF由三个类组成. iRSFSource 数据源 iRSFFilter 过滤器 iRSFSorter 排序器 iRSF 使用: iRsf = new iRSF(); iRsf.draw = function(data){ //展现列表,data的结构为{property:[{data1},{data2}]},* property 可以自定义,由iRSFSource 指定

java web过滤器实际应用(解决中文乱码 html标签转义功能 敏感字符过滤功能)

转载地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求. 一.Decorator设计模式 1.1.Decorator设计模式介绍 当某个对象的方法不适应业务需求时,通常有2种方式可以对方法进行增强: 编写子类,覆盖需增强的

Django 支持自定义表头和根据数据库某字段生成多个sheet的excel下载

工作需要,需要做下载excel的功能,同时根据数据库的某个字段完成多sheet的功能. 由于用处较多,封装了一个函数. add_worksheet: 为生成多个sheet的方法 from io import BytesIO import xlsxwriter def download_excel(cursor, sql_field_index=False, custom_headers=False, sheet_title="worksheet_1"): ""&qu

含有过滤功能的android流式布局

FilterFlowLayout 含有过滤功能的流式布局, 参考FlowLayout 可以去除宽度不在范围(比例或真实值)内的子view 可以设置最大行数 可以添加组件间水平间距 可以添加行间距 系统要求 Android 4.0以上 快速使用 <me.codeboy.android.lib.FilterFlowLayout xmlns:cb="http://schemas.android.com/apk/res-auto" android:id="@+id/filter

邮箱客户端的邮件过滤功能

虽然现在各种联系工具很发达,各种社交工具,但是邮件这种方式还是非常常用,也是非常重要的.公司邮箱,各种网站注册账号使用的邮箱等,既然有了邮箱,那么就要收发邮件,经常收发邮件,还是有一个客户端最方便了. 但是随着收发邮件多了,带来一个问题,各种已读邮件充斥在收件箱和发件箱中,各种订阅邮件聚集在一个收件箱中,顿时使一个小小的收件箱显得拥挤起来,邮件的检索也变得异常困难,这时如果有一个邮件分类过滤的功能该多好啊,别急,下面就一起看看常见的邮箱客户端的分类功能. Foxmail邮件转移功能 最初使用Fo

Qt自定义菜单项

经常会看到一些菜单的部分项是由几个按钮组成的,如酷狗.QQ.360都有类似菜单,对于常规的菜单项,图标 + 文字 实现一个事件,很容易完成,那么怎么自定义菜单项呢? Qt提供了支持,就是利用QWidget + QWidgetAction来完成.QWidgetAction继承自QAction,无法通过继承来实现一个界面,但它提供了setDefaultWidget来绑定一个界面,使用起来就更加方便了. 下面实现一个没有Action的菜单,并通过按钮显示出来: void UserMenu::Creat

HTML格式自定义OpenCart邮件模板功能插件

HTML格式自定义OpenCart邮件模板功能插件 HTML格式自定义OpenCart邮件模板功能插件 前台演示网址后台登录信息: 用户名: demo 密码: demo后台演示网址型 号: COC-A0003 ¥100.00 税前: ¥100.00购买所需积分: 80 购买数量: +- * 扩充功能安装:              --- 请选择 ---                          自己安装                                         

QT自定义精美换肤界面

陆陆续续用QT开发过很多项目,也用QT写过不少私活项目,也写过N个工具,一直梦寐以求能像VC一样可以很方便的有个自定义的界面,QSS的强大让我看到了很好的希望,辗转百度谷歌无数次,一直搜索QT相关的换肤文章,绝大部分的是一些简单的按钮文本样式,要做到整体换肤程度几乎不行,QTCN论坛里的奋斗的孩子写了个模仿360安全卫士系列,让我既惊喜有遗憾,惊喜的是能够用QT实现一个这么完整的360安全卫士界面,确实不错,也支持多种换肤,遗憾的是我下载过的是VC版本的,对于一直执着于用Qt Creator 来