1. 写在前面

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

2. 过滤提示

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

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

void CFilterHeaderView::mouseMoveEvent(QMouseEvent *e)
{
m_hover = logicalIndexAt(e->pos());
if (m_hover != -)
updateSection(m_hover);
QHeaderView::mouseMoveEvent(e);
} bool CFilterHeaderView::event(QEvent *e)
{
switch(e->type())
{
case QEvent::Leave:
case QEvent::HoverLeave:
if (m_hover != -)
updateSection(m_hover);
m_hover = -;
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 != -)
updateSection(m_press);
QHeaderView::mousePressEvent(e);
} void CFilterHeaderView::mouseReleaseEvent(QMouseEvent *e)
{
m_press = -;
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), , 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();
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

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

  1. 转--Android实现ListView过滤功能,继承于BaseAdapter,非ArrayAdapter。

    其实实现ListView过滤功能最方便的便是使用ArrayAdapter,里面自带的getFilter()方法能很方便的实现此功能,但是在实际的开发中,一般都是继承于BaseAdapter.还有一种是 ...

  2. QTableWidget自定义表头QHeaderView加全选复选框

    1         QTableWidget自定义表头QHeaderView加全选复选框 在使用QTableWidget时需要在表头添加全选复选框,但是默认的表头无法添加复选框,只能用图片画上去一个复 ...

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

    转载地址:http://www.cnblogs.com/xdp-gacl/p/3952405.html 在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可 ...

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

    IRSF 是由javascript编写,iRSF快速简单易用的实现列表.排序.过滤功能(该三种操作以下简称为 RSF ). iRSF由三个类组成. iRSFSource 数据源 iRSFFilter ...

  5. Qt自定义标题栏

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt自定义标题栏     本文地址:http://techieliang.com/2017/1 ...

  6. Django 中自定义 Admin 样式与功能

    目录 自定义 Admin 样式与功能 1 页面修改中文 1.1 语言设置为中文 1.2 应用管理设置为中文 1.3 数据库表设置为中文 1.4 数据库表字段名称修改为中文 2 修改后台样式 2.1 安 ...

  7. Spring Security学习笔记-自定义Spring Security过滤链

    Spring Security使用一系列过滤器处理用户请求,下面是spring-security.xml配置文件. <?xml version="1.0" encoding= ...

  8. element ui table render-header自定义表头信息使用

    在使用vue自定义组件内容过程之中,我们绝大多数情况下都是通过预先写好不同的html模板,再通过props传入不同的值来渲染不同的模板.例如我们需要实现一个<v-title size='1'&g ...

  9. WPF DataGrid 复合表头 (实现表头合并,自定义表头)

    功能说明: 将 DataGrid嵌套在本控件内,使用Label自定义表头,如果需要上下左右滚动 需要在控件外围添加  ScrollViewer 并且设置  ScrollVisibility 为Auto ...

随机推荐

  1. C#使用Selenium实现QQ空间数据抓取 说说抓取

    上一篇讲的是如何模拟真人操作登录QQ空间,本篇主要讲述一下如何抓取QQ说说数据 继续登录空间后的操作 登陆后我们发现QQ空间的菜单其实是固定的,只需要找到对应元素就可以,继续XPath 可以得到地址 ...

  2. TASM 5.0 安装及使用教程

    安装TASM 5.0很简单,您只需要下载本站[相关工具]中的"TASM50.zip"文件,解压后在Windows9x/NT下执行"INSTALL.EXE"即可开 ...

  3. Adapter的泛型

    宗旨:GetView方法放在具体的Activity/Fragment里面实现,其他的均可以复用 /// <summary> /// 通用适配器:新建GetViewEvent委托+OnGet ...

  4. ASP .NET 返回Json操作结果

    返回string var A="..."; var B="..."; $.ajax({ type: "POST", url: "/ ...

  5. Styling a ListView with a Horizontal ItemsPanel and a Header

    原文http://eblog.cloudplush.com/2012/05/23/styling-a-listview-with-a-horizontal-itemspanel-and-a-heade ...

  6. Windows程序设计画图实现哆啦A梦

    在看雪论坛上看到的一个帖子,很喜欢,转载一下.原文地址:http://bbs.pediy.com/showthread.php?t=138630哆啦A梦是画出来的,不知道作者算这些坐标位置算了多久,真 ...

  7. git 专题

    $ git pull origin test // git pull合并代码的时候,若发生冲突,会处于merging状态,检查代码,发现自己的分支低于主分支,这个时候想撤销merge // 撤销mer ...

  8. Android零基础入门第40节:自定义ArrayAdapter

    原文:Android零基础入门第40节:自定义ArrayAdapter ListView用起来还是比较简单的,也是Android应用程序中最重要的一个组件,但其他ListView可以随你所愿,能够完成 ...

  9. DBLINK学习

    1.连接本地scott用户查看拥有的表 [oracle@ORADG ~]$ sqlplus scott/tiger SQL> select * from tab; TNAME           ...

  10. cairo 图形库

    简介 提到cairo,估计很少知道这还是一个图形库的名字(http://cairographics.org),Linux的两大流行桌面环境KDE和Gnome,其对应的基础组件是QT和GTK+,相对于框 ...