文章目录

  • 一、开心一刻
  • 二、概述
  • 三、效果展示
  • 四、任务需求
  • 五、指定列排序
  • 六、排序
  • 七、列对其方式
  • 八、相关文章

原文链接: QRowTable表格控件(二)-红涨绿跌

一、开心一刻

一天,五娃和六娃去跟蛇精决斗,决斗前有这样一段对话。

五娃:“妖精!今天我俩就要消灭你!今天就是你的死期!”

蛇精:“呵呵呵,真是可笑。你们自己个儿都是从树上长出来的,凭什么叫我妖精?!”

五娃:“你也说了,我们是从树上长出来的,是葫芦变的,自然不是妖精。”

蛇精:“你们不是妖精,难道还是神仙了,再难不成你把自己当人了?”

五娃和六娃异口同声道:“哈哈哈哈哈哈!你说对了,我就是人,是植!物!人!”

二、概述

最近工作比较忙,不过还是抽时间把这个表格组件继续完善下去。

Qt的自带的表格控件非常强大,支持各种方便操作,上一篇文章QRowTable表格控件-支持hover整行、checked整行、指定列排序等介绍了一个简单的demo,主要是做一个股票表格控件,而他天然的就是支持hover和checked行特性,对Qt比较熟悉的同学可能都知道Qt其实有两个接口,可以设置交互行为为选择行。

接口就是这两个货了。

setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QTableView::SingleSelection);//不能多选

既然Qt已经有接口了,为什么我们还要自己写这个控件呢!

尝试过用Qt的接口设置相关行为的同学我相信最后都会发现是什么原因,这里我直接把原因放出来。

  1. 首先我们的需求是每一行的文字颜色是不一样的,Qt表格默认的行为是:表格cell如果被选中,前景色和背景色则是从高亮role中拿到的色值,以下代码是一个示例代码,其中的QPalette::HighlightedText和QPalette::Highlight就是存储单元格被选中时,绘制的颜色。
view_option.palette.setColor(QPalette::HighlightedText, index.data(Qt::ForegroundRole).value<QColor>());view_option.palette.setColor(QPalette::Highlight, index.data(Qt::BackgroundRole).value<QColor>());
  1. 最重要的时候我们自己还是实现了一堆的小需求,下一小节我们来一个个分析

三、效果展示

以下是红涨绿跌效果图,实现功能一样。

UI展现形式不一样,但是都实现了红涨绿跌

  1. 背景色不同
  2. 排序效果不同

纯白版

腹黑版

四、任务需求

看过效果图之后,有没有发现我们这里的表格控件和Qt自带的控件有什么区别呢?其实这里我们要达到gif展示的那种效果,还是使用了很多实现技巧。

控件都包含哪些功能呢?

  1. 指定列排序

指定列排序,这个版本的代码经过了优化,比QRowTable表格控件-支持hover整行、checked整行、指定列排序等这篇文章中将的版本要更优雅一些。

  1. 排序图标

纯白版使用的是Qt排序图标

腹黑版排序图标使我们自己去绘制的,并且绘制水平表头时文本有特殊处理

  1. 列内容对其方式

看到这里的同学不放自己也可以先思考下,看这3种需求的实现方式,有了大致思路后在继续往下看。

这样带着思路看,理解起来应该更加的容易。

五、指定列排序

还记得上一篇文章QRowTable表格控件-支持hover整行、checked整行、指定列排序等中怎么禁用指定列排序吗?忘记的同学可以到这篇文章中去熟悉下,我记着应该是发现排序列不允许被排序时,直接禁用排序功能。

本篇文章我们使用了一种更加优雅的方式来阻止指定列排序。

首先我们重写了表头组件,并且重写了mouseReleaseEvent这个函数,因为这个函数中才触发了排序,因此这个函数中足以过滤掉不让排序的列。

class QRowHeader : public QHeaderView
{Q_OBJECTpublic:QRowHeader(Qt::Orientation orientation, QWidget * parent = nullptr);public://设置是否支持排序void SetSortEnable(int logicalIndex, bool enable);signals:void MouseMove();protected:virtual void mouseMoveEvent(QMouseEvent * event) override;virtual void mouseReleaseEvent(QMouseEvent *e) override;virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override;private:QMap<int, bool> m_Indicator;
};

然后代码是这样处理的,代码量不大,就是判断鼠标点击的位置如果是禁止排序的列,我们直接把事件循环中断啦!!!

是不是很坏,哈哈哈

void QRowHeader::mouseReleaseEvent(QMouseEvent * event)
{int column = logicalIndexAt(event->pos().x());if (m_Indicator.contains(column) && m_Indicator[column] == false){return;}QHeaderView::mouseReleaseEvent(event);
}

六、排序

上边讲完了怎么去阻止排序,重写了QHeaderView。

virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override;

里边有paintSection这样的函数,他就是绘制表头一个单元格所产生的回调。

在这个函数里边首先调用父窗口绘制表头,然后如果发现自己是排序列时,顺道去绘制一个排序图标.

代码很容易理解,绘制朝上还是朝下的图标取决于我们当前的排序方式

void QRowHeader::paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const
{...//绘制三角形if (sortIndicatorSection() == logicalIndex){QRect indicator = rect;indicator.setLeft(indicator.right() - 6);indicator.setHeight(10);indicator.moveTop((rect.height() - indicator.height()) / 2);indicator.moveLeft(indicator.left() - 10);//距离左边界10像素if (sortIndicatorOrder() == Qt::AscendingOrder){painter->drawPixmap(indicator, QPixmap(":/QRowTable/down_arrow.png.png"));}else if (sortIndicatorOrder() == Qt::DescendingOrder){painter->drawPixmap(indicator, QPixmap(":/QRowTable/up_arrow.png.png"));}}
}

绘制列头中的项时,如果当前列是排序列,那么这里就需要绘制排序图标。如果刚好这一列的文字是右对齐呢,正常情况下我们的图标还有文字可能是没有问题的。

如果该列很窄,那么排序图标和列cell中的文字可能会重叠

既然有概率重叠,这里我们就需要处理这个异常,当出现上述这种情况时,我们需要改变原有的文字绘制区域,不让他在图标的绘制区域绘制文本。

还是重写paintSection方法,这个是绘制列头一个单元格的方法。

看如下代码,首先我们填充了这个cell,为什么呢?不着急回答这个问题,接着往下看,我们把原有的rect向左便宜了16个像素,然后绘制列头cell。

void QRowHeader::paintSection(QPainter * painter, const QRect & rect, int logicalIndex) const
{painter->fillRect(rect.adjusted(-1, 0, -1, -1), QColor("#212121"));painter->save();QRect r = rect;if (sortIndicatorSection() == logicalIndex){r.adjust(0, 0, -16, 0);}QHeaderView::paintSection(painter, r, logicalIndex);painter->restore();painter->setPen(QColor("#2B2B2B"));painter->drawRect(rect.adjusted(-1, 0, -1, -1));...

这样会有什么问题?仔细想想,文字绘制没问题,其实有问题的是背景色绘制会发现错误

因此我们在函数开头先把列头cell背景色进行了填充,这个背景色其实就是列头cell的背景色

setStyleSheet("QTableView{background:#333333;}""QHeaderView{background:#212121;color:gray;}""QHeaderView:section{padding:6px;border:0;background:#212121;color:gray;}");

上边是这个组件的qss样式,表头cell的背景色其实就是#2212121,因此填充区域我们也使用了这个色值,最终达到我们预期的效果。

这里插一句:绘制时一定要注意绘制的顺序,否则我们自定义的绘制可能会和Qt自己的绘制有冲突。这里尽量考虑清楚,免得产生冲突。

当列表头被点击时,QRowHeader对象会发出列cell被点击信号sectionClicked,这个信号也是从鼠标弹起函数mouseReleaseEvent中触发。

connect(m_pHHeader, &QRowHeader::sectionClicked, m_pFilter, &QFilterModel::setFilterKeyColumn);
connect(m_pHHeader, &QRowHeader::sectionClicked, this, [this](int column){if (column == 0 || column == 1 || column == 2){GetFilterModel()->SetCompareType(QFilterModel::CT_INT);}else{GetFilterModel()->SetCompareType(QFilterModel::CT_STRING);}
});

sectionClicked信号触发后,这里干了两件事:设置当前的排序列和当前的排序方式。

SetCompareType接口用于设置当前排序方式。

目前这个组件支持3中排序方式,数字、百分比和字符串

bool QFilterModel::lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const
{if (m_eType == CT_INT){double l = source_left.data().toDouble();double r = source_right.data().toDouble();return l < r;}else if (m_eType == CT_PERCENT){double l = source_left.data(Qt::UserRole + 2).toString().remove("%").toDouble();double r = source_right.data(Qt::UserRole + 2).toString().remove("%").toDouble();return l < r;}else{QString l = source_left.data().toString();QString r = source_right.data().toString();return l < r;}
}

这里需要说明一下,百分比为什么要单独拿出来分一类,设计之初,百分比和数字是放在一类中去比较的,但是后来发现百分比没有办法存储在double中,因此添加了百分比分类。这里也不强制非要添加一个新类,其他能实现比较需求的办法均可。

七、列对其方式

Qt的文字对其方式有如下这么多,然后我们这个组件支持比较主流的集中排序方式,分别是:水平居左、水平居中、水平居右

水平居右时,如果当前列时排序列,我们文字绘制的位置区域不能包含排序图标的大小,否则文字可能和图标重叠

enum AlignmentFlag {AlignLeft = 0x0001,AlignLeading = AlignLeft,AlignRight = 0x0002,AlignTrailing = AlignRight,AlignHCenter = 0x0004,AlignJustify = 0x0008,AlignAbsolute = 0x0010,AlignHorizontal_Mask = AlignLeft | AlignRight | AlignHCenter | AlignJustify | AlignAbsolute,AlignTop = 0x0020,AlignBottom = 0x0040,AlignVCenter = 0x0080,AlignBaseline = 0x0100,// Note that 0x100 will clash with Qt::TextSingleLine = 0x100 due to what the comment above// this enum declaration states. However, since Qt::AlignBaseline is only used by layouts,// it doesn't make sense to pass Qt::AlignBaseline to QPainter::drawText(), so there// shouldn't really be any ambiguity between the two overlapping enum values.AlignVertical_Mask = AlignTop | AlignBottom | AlignVCenter | AlignBaseline,AlignCenter = AlignVCenter | AlignHCenter
};

控件之外,我们通过SetAlignment接口设置了该列的排序方式,排序方式对列的内容和列头都起作用。也就是说列头和列内容排序方式是一致的。

model->SetAlignment(0, Qt::AlignRight | Qt::AlignVCenter);
model->SetAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
model->SetAlignment(2, Qt::AlignRight | Qt::AlignVCenter);
model->SetAlignment(3, Qt::AlignLeft | Qt::AlignVCenter);
model->SetAlignment(4, Qt::AlignLeft | Qt::AlignVCenter);
model->SetAlignment(5, Qt::AlignLeft | Qt::AlignVCenter);

列头绘制时,会通过headerData接口拿文字对其方式,然后这里只需要返回之前使用SetAlignment接口设置的对其方式即可。

QVariant QRowModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const
{if (Qt::TextAlignmentRole == role){//Q::AlignLeft | Qt::AlignVCenterauto iter = m_AlignmentList.find(section);if (iter != m_AlignmentList.end()){return iter->second;}return Qt::AlignCenter;//return m_AlignmentList.at(section);}return QStandardItemModel::headerData(section, orientation, role);
}

补充

重新换了一种方式实现第五节的mouseReleaseEvent函数。

之前的方法在开启了列拖拽之后会出现问题

void QRowHeader::mouseReleaseEvent(QMouseEvent * event)
{int column = logicalIndexAt(event->pos().x());if (m_Indicator.contains(column) && m_Indicator[column] == false){setSectionsClickable(false);QHeaderView::mouseReleaseEvent(event);setSectionsClickable(true);}else{QHeaderView::mouseReleaseEvent(event);}
}

八、相关文章

  1. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等

  2. Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格

  3. 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)

  4. 超级实用的属性浏览器控件–QtTreePropertyBrowser

  5. Qt之表格控件蚂蚁线

  6. QRowTable表格控件-支持hover整行、checked整行、指定列排序等

如果您觉得文章不错,不妨给个 打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!

很重要–转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


QRowTable表格控件(二)-红涨绿跌相关推荐

  1. QRowTable表格控件-支持hover整行、checked整行、指定列排序等

    文章目录 一.开心一刻 二.嘴一嘴 三.效果展示 四.浅谈实现 五.自定义数据源 1.data函数 2.flags函数 六.自定义视图 1.目的 2.问题分析 七.测试 八.相关文章 原文链接: QR ...

  2. 股市红涨绿跌色系定义真的是中国特色吗?

    20080809 郑昀@玩聚 与G共舞刚才发表的<适应中国特色 谷歌财经图标改绿色为红色.>,提及"在其他证券交易所,股市上涨都是使用绿色,下跌使用红色,唯独中国大陆的沪深股市, ...

  3. 文华财经期货量化短线策略支撑压力指标公式,短线行情无未来函数多空均线红涨绿跌信号

    很多人从行情历史走势图发现,金叉行情上涨,死叉行情下跌的规律,告诉大家那些完美冬形只是过去式而已,行情震荡时,指标失灵可以把你震荡到爆仓.我们也会经常发现不好的指标在很多情况下会相互矛盾,这个指标显示 ...

  4. 文华财经期货量化高抛低吸程序化指标公式,无未来函数红涨绿跌多空均线系统信号

    期货指标公式的万变不离......几乎所有公式都要用到价格,收盘价.开盘价.最高最低价. 最具代表的就是均线和macd.而他们想反映的,无非是对趋势的一种预判. 各种指标的买卖点,也就是想找出趋势确立 ...

  5. SpreadJS 纯前端表格控件应用案例:在线问卷系统

    由某软件公司研发的在线问卷系统,是一款通过收集网络信息,帮助问卷设计者和数据分析师们分析消费者线上行为特征和态度的系统平台,使用该系统可批量而精确地抽取目标网页中的任何数据及信息,快速实现实时的信息获 ...

  6. SAP UI5 应用开发教程之六十二 - 基于 OData V4 的 SAP UI5 表格控件使用方法介绍试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  7. 专题一:Labview表格控件 及 应用(二)

    标题专题一:Labview表格控件 及 应用(二) 最近一段时间,做试验台上位机编程,老是用到表格控件,这几天抽时间专门写一个表格控件的专题.有用到的朋友可以参考一下. 上一讲介绍了表格控件,认识了一 ...

  8. extjs 表单设置html5,ExtJS 配置和表格控件使用

    ExtJS是一套完整的RIA解决方案,也因为功能完整造成了ext-all.js有400多k,由于是基于JS和CSS的功能实现,对客户端机器性能也有一定的要求,即不支持IE6以下的版本.如果您的项目对网 ...

  9. 纯前端表格控件SpreadJS V12.1 隆重登场,专注易用性,提升用户体验

    ​ 一款优秀的开发工具,在更新迭代中,除了要满足不同场景的业务需求,也需不断优化已有功能,尤其是细节方面,要能为用户带来使用体验和开发效率的提升. 作为一款备受业界专家和开发者认可的纯前端类Excel ...

最新文章

  1. 如何高效地爬取链家的房源信息(一)
  2. EXSI 连接硬件USB pass-through
  3. memcached的基本命令(安装、卸载、启动、配置相关)
  4. python三十六:shelve模块
  5. 面对不可避免的故障,我们造了一个“上帝视角”的控制台
  6. 云计算设计模式(四)——消费者的竞争模式
  7. EMNLP 2022 和 COLING 2022,投哪个会议比较好?
  8. 多线程测试时的辅助类--CountDownLatch
  9. android surfaceview view 区别
  10. 如何在物理机上安装Centos操作系统(实体机物理机)
  11. 计算机网络原理最详细解说
  12. 关于 onchange,onpropertychange,oninput事件
  13. excel Cell函数
  14. Pyspark获取hdfs上多个文件
  15. 和平精英体验服服务器怎么样维护,和平精英体验服账号怎么弄_体验服官网申请教程_3DM手游...
  16. 听比喻,懂原理(1)超五类双绞线和六类双绞线的区别
  17. Oracle数据库查询十个小技巧
  18. 图论 SCC(CCF高速公路)
  19. 老邹寻找Magento商业合作伙伴
  20. Kotlin 第一弹:自定义 ViewGroup 实现流式标签控件

热门文章

  1. 同一款衣服,杨幂成爆款女王,而唐嫣却朴素似路人
  2. 探花交友_第4章_圈子功能实现
  3. 王昊奋:大规模知识图谱技术
  4. Unity组件_车轮碰撞器
  5. 时尚界新宠,高级穿搭1+1
  6. linux 下切换集成显卡和独立显卡,禁用独显,解决发热问题
  7. [2021版]安卓7.0/8/9/10以上+ROOT+雷电模拟器/小米10/真机+Fiddle抓包Https
  8. html5脸型捕捉,圆脸变瓜子脸的最快办法 5款发型让肉肉脸秒变V型小脸
  9. std::sort 用法
  10. 优秀课程案例:使用Scratch制作愤怒的小鸟天空版!