找回密码
 立即注册
收起左侧

【独家连载】Qt进阶003:像Excel一样在列标题中绘制过滤指...

1
回复
1371
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-9-16 22:19:15 显示全部楼层 |阅读模式
本帖最后由 baizy77 于 2018-9-28 10:32 编辑

原创文章,转载请注明出处。
----------------------------------------------------------------------------
引言
----------------------------------------------------------------------------------------------------------------------
       使用Qt3的时候我们还用QTableWidget绘制表格,但是Qt的更高版本中提供了MVC支持,这为面向对象编程提供了更好的手段。在更高版本的Qt中,提供了QTableView来绘制表格,程序员只需为view设置Model就可以了,这极大简化了编程。但是单纯的表格展示有时候不满足我们的使用,有时候,我们也需要像Excel一样进行过滤并在列标题中绘制过滤指示符以便方便的展示哪些列可以过滤,哪些列已经执行了过滤,那么在Qt中该怎么做呢?
正文
----------------------------------------------------------------------------------------------------------------------
       QTableView提供行标题、列标题视图(QHeaderView),也就是我们通常所说的表头。我们如果要进行过滤,一般会设置列的数据类型,然后根据数据类型进行过滤。为了简化起见,我们仅对标题的绘制部分进行着重介绍。
      // cheaderview.h
  1. class CHeaderVieww : public QHeaderView {
  2.        public:
  3.    ........
  4.        public:

  5.     // 重置列
  6.     void CHeaderView::resetColumnCount(int count);
  7.     // 设置某列是否处于过滤状态
  8.     void setFilterFlag(int column, bool bEnable);
  9.     // 绘制列标题
  10.     void PaintSection(QPainter* painter, const QRect& rect, int logicalIndex) const;
  11. private:
  12.     std::vector<bool> m_vFilterFlag;     /// 当前过滤状态
  13. };
复制代码
   
    // cheaderview.cpp
  1. void CHeaderView::resetColumnCount(int count) {
  2.     m_vFilterFlag.resize(count);
  3.     for (int i = 0; i < count; i++)    {
  4.         m_vFilterFlag[i] = false;
  5.     }
  6. }
复制代码
                指定的列进入过滤状态,本接口由过滤选择界面调用:
  1. void CHeaderView::setFilterFlag(int column, bool bEnable)
  2. {
  3.     if (column < m_vFilterFlag.size())
  4.     {
  5.         m_vFilterFlag[column] = bEnable;
  6.     }
  7.     viewport()->update();
  8. }
复制代码
              绘制过滤指示符接口:
  1. static const int c_nFilterButtonWidth= 20; // 过滤按钮宽度
  2. static const int c_nAdjustLength = 5; // 光标改为调整列宽时的范围

  3. void CHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const {
  4.     QRect rct = rect;
  5.     rct.setWidth(rect.width() - c_nFilterButtonWidth - c_nAdjustLength);
  6.     painter->save();

  7.     // 需要先调用父类接口,再绘制自己的内容,否则自己的内容会被父类绘制的内容遮盖。
  8.     CGPHeaderView::paintSection(painter, rct, logicalIndex);
  9.     painter->restore();
  10.     // 我们希望表格在视图中不要太突出,最好跟背景融为一体,这样比较协调。
  11.     painter->setBrush(palette().background());

  12.     QRect rectButton(rect.right() - c_nFilterButtonWidth - c_nAdjustLength, rect.y(),
  13.         c_nFilterButtonWidth, rect.height());
复制代码
  1.         QStyleOptionButton option;
  2.         option.features = QStyleOptionButton::Flat;
  3.         option.rect = rectButton;
  4.         option.palette = palette();
  5.         rectButton.adjust(0, 2, -1, -3);
  6.         painter->drawRoundRect(rectButton, 2, 2);        

  7.         if (m_vFilterFlag[logicalIndex]) // 绘制过滤标志
  8.         {
  9.                 QRectF rctStandard(0, 0, 18, 22);
  10.                 rctStandard.moveCenter(rectButton.center());
  11.                 QVector<QPointF> vPoints;
  12.                 vPoints << QPointF(rctStandard.left() + 1 / 3.*rctStandard.width(), 1 / 4. * rctStandard.height() + rctStandard.top())
  13.                         << QPointF(rctStandard.left() + 11 / 12.*rctStandard.width(), 1 / 4. * rctStandard.height() + rctStandard.top())
  14.                         << QPointF(rctStandard.left() + 17 / 24. * rctStandard.width(), 1 / 2. * rctStandard.height() + rctStandard.top())
  15.                         << QPointF(rctStandard.left() + 17 / 24. * rctStandard.width(), 3 / 4. * rctStandard.height() + rctStandard.top())
  16.                         << QPointF(rctStandard.left() + 13 / 24. * rctStandard.width(), 3 / 4. * rctStandard.height() + rctStandard.top())
  17.                         << QPointF(rctStandard.left() + 13 / 24. * rctStandard.width(), 1 / 2. * rctStandard.height() + rctStandard.top());
  18.                 QPolygonF polygon(vPoints);
  19.                 QBrush brsh(Qt::black, Qt::SolidPattern);
  20.                 painter->setBrush(brsh);
  21.                 QPen pn(Qt::NoPen);
  22.                 painter->setPen(pn);
  23.                 painter->drawPolygon(polygon);
  24.                 vPoints.clear();
  25.                 vPoints << QPointF(rctStandard.left() + 1 / 8.*rctStandard.width(), 5 / 8. * rctStandard.height() + rctStandard.top())
  26.                         << QPointF(rctStandard.left() + 7 / 16. * rctStandard.width(), 5 / 8. * rctStandard.height() + rctStandard.top())
  27.                         << QPointF(rctStandard.left() + 9 / 32. * rctStandard.width(), 13 / 16. * rctStandard.height() + rctStandard.top());
  28.                 QPolygonF polygon1(vPoints);
  29.                 painter->drawPolygon(polygon1);
  30.         }   
复制代码
  1. }
复制代码

    而为提供过滤功能,还需要像Excel一样在点击过滤指示符(小三角)时弹出过滤配置界面,这需要和QTableViewmodel结合起来共同实现。鉴于篇幅有限,过滤选择界面不在本节介绍。纸质教材或者视频教材会有配套的完整源代码可供参考。感兴趣的话可以关注。
结语
----------------------------------------------------------------------------------------------------------------------
       使用表格的过滤功能,可以为引用程序增加更多的功能和灵活性以及更好的交互手段,使数据的展示不再枯燥而是变得多样,也能为应用程序的展示加分。要知道,表格不仅能用在widget中,还能用在QGraphicsItem中哦,那样的话,可以把表格完美的嵌入我们的图形中进行展示,还可以支持交互,很不错的设计吧。
===========================================================
本教程的纸质书籍正在编写中,课程视频也在录制中,敬请关注。
===========================================================

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-17 07:36:06 显示全部楼层
很抱歉,第一次提交的代码不全。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册