Qt自定义表头实现过滤功能的方法

 更新时间:2019年07月08日 10:23:09   作者:随性者也  
这篇文章主要个给大家介绍了关于Qt自定义表头实现过滤功能的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用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

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

您可能感兴趣的文章:

相关文章

  • Objective-C 消息传递机制详解

    Objective-C 消息传递机制详解

    Objective-C语言中方法的传递有二种:①Selector ② Blocks,本文主要说一下Selector,本文以Objective-C 消息传递机制进行详细介绍,关于Blocks会在后续总结一下
    2012-11-11
  • C++基于特征向量的KNN分类算法

    C++基于特征向量的KNN分类算法

    这篇文章主要为大家详细介绍了C++基于特征向量的KNN分类算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • c++ 有趣的动态转换

    c++ 有趣的动态转换

    这篇文章主要介绍了c++ 动态转换的相关资料,帮助大家更好的理解和使用c++编程,感兴趣的朋友可以了解下
    2020-09-09
  • C++ Qt实现浏览器网页内嵌的音视频播放器

    C++ Qt实现浏览器网页内嵌的音视频播放器

    这篇文章主要为大家详细介绍了如何利用C++ Qt实现浏览器网页内嵌的音视频播放器,并支持软硬解码,支持音频,支持录像截图,支持多路播放等,感兴趣的可以了解下
    2024-01-01
  • C++ std::copy与memcpy区别小结

    C++ std::copy与memcpy区别小结

    本文主要介绍了C++ std::copy与memcpy区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • C语言超详细讲解轮转数组

    C语言超详细讲解轮转数组

    这篇文章主要给大家讲解轮转数组的问题,一个问题不局限于一种解法,希望你看了本文的解决方法以后可以举一反三自己编写,这样你的技术水平会有质的提高
    2022-04-04
  • VS2019开发Linux C++程序的实现步骤

    VS2019开发Linux C++程序的实现步骤

    由于很多unix特有的函数无法在Windows上使用,而Vim又用的不太顺手,突然想到最初用vs的时候有一个基于Linux的C++开发。本文就来介绍一下,感兴趣的可以了解一下
    2021-07-07
  • C++单例模式为何要实例化一个对象不全部使用static

    C++单例模式为何要实例化一个对象不全部使用static

    这篇文章主要介绍了C++单例模式为何要实例化一个对象不全部使用static,文基于C++围绕主题展开详细内容,需要的小伙伴可以参考一下
    2022-05-05
  • 自己模拟写C++中的String类型实例讲解

    自己模拟写C++中的String类型实例讲解

    下面小编就为大家带来一篇自己模拟写C++中的String类型实例讲解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • C++深入浅出讲解希尔排序算法的实现

    C++深入浅出讲解希尔排序算法的实现

    希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现
    2022-05-05

最新评论