[TOC]html
原文连接:QRowTable表格控件(五)-重写表头排序、支持第三次单击恢复默认排序程序员
1、原生表格
开发客户端程序的方式愈来愈多了,如今很流行的libcef、electron等等均可以做为快速开发客户端软件的方案,可是若是须要一个好的用户体验,仍是离不开原生化的开发,虽然慢,可是性能好啊。浏览器
说到原生化开发,那对应的UI库相对较多,流行的就有Qt、soui、duilib、还有老掉牙的MFC和其余一些第三方公司开源维护的directUI库等等。网上找到一篇整理的文章,有兴趣的同窗能够参考C++界面库。框架
目前C++客户端使用最普遍的就是UI框架就是Qt,它不只包含了GUI控件,更多的实际上是一种解决方案,使用过Qt的同窗都比较清楚,Qt的安装动态库有几十个之多,但是若是你只想使用Qt的GUi模块的话,就只须要包含3个动态库便可,他们分别是核心模块QtCore、Gui模块QtGui和QtWidget。electron
当咱们将Qt做为咱们的开发SDK时,大多数时候原生的控件+qss美化就能够完成咱们的需求,然而总有一些特殊状况,好比产品经理脑残的时候、或者说是业务场景傻逼了,老是须要完成一些奇奇怪怪交互,那么咱们就须要重写原生的控件实现方式。函数
今天就来讲一个案例--表格控件列排序方式。性能
对于某一些特殊的场景下,咱们的表格展现的数据可能须要排序,这样的表格控件Qt已经给咱们提供好了,只须要咱们从写一些类和接口便可。前边已经写了4篇关于表格控件的功能,分别是QRowTable表格控件-支持hover整行、checked整行、指定列排序等、QRowTable表格控件(二)-红涨绿跌、QRowTable表格控件(三)-效率优化之-合理使用QStandardItem和QRowTable表格控件(四)-效率优化之-优化数据源,感兴趣的同窗能够去看看。字体
不幸的是Qt自带的表格排序功能,便是咱们冲写完全部接口依然不能知足负责的业务需求--表格表头连续3点三次是一个循环,什么意思呢?优化
传统表格排序ui
Qt自带的表格排序行为是这样的,默认状况是不排序的,咱们能够经过接口开启排序,或者经过接口设置不排序,当咱们启用排序规则后,假设说咱们的表格点击点击一下是降序,点击第二下就是升序,再次点击是又会恢复到降序规则,这样是否是还挺完美呢!
这个时候产品有话说了,点击第三次时,须要设置程序为不排序。
程序员:卧槽。。。。你说什么。。。。听不到。。。。
新的排序规则
在传统表格排序的基础上作一下调整
- 能够支持某些列不容许排序
- 3次连续单击为一个循环,也就是降序-升序-无序这样3个状态循环
不得不说产品的脑洞仍是很大的。既然产品都说想要这个功能了,那么有时间仍是得考虑下。跟产品沟通良久后,有了以下安排,虽然这个功能对用户来讲不是一个特别须要的功能,可是当咱们的软件功能稳定后,迭代没有那么着急的时候,是否是能够考虑研究下这个而功能呢。
而后也就有了本篇文章
虽然重写了Qt自己的逻辑,没想到仍是能够实现的!!!
2、效果展现
按照惯例先上图,看看是否是同窗们想要的功能。
<center> <img src="https://images.cnblogs.com/cnblogs_com/swarmbees/1497876/o_row_table_sort.gif" /> </center>
3、实现方式
新的表格排序有2个点须要咱们去思考,分别是某些列排序、排序交互修改,下面咱们分开来去实现
一、排序列定制
Qt默认提供了可排序接口,可是开启后咱们全部的列都支持排序了,这个时候咱们就须要研究Qt的源码,看看Qt的排序是怎么触发的,而后在合理的时机去加上咱们不支持排序的逻辑
博主这里找到的作法是重写QHaderView这个类,并重写实现了鼠标按下并抬起的接口,在这个接口中判断咱们业务层是否是容许排序。
重写后的逻辑是这样的
-
若是不容许排序,咱们先调用Qt原有的接口禁用全部列排序功能
-
调用父类的鼠标抬起函数
-
若是不容许排序,须要调用Qt原有的接口启用全部列排序功能
以上逻辑的步骤2是原有的逻辑,步骤1和步骤3分别是在进行业务逻辑判断后进行的逻辑调整,达到咱们禁用某些列排序的功能
void QRowHeader::mouseReleaseEvent(QMouseEvent * event) { int column = logicalIndexAt(event->pos().x()); if (m_Indicator.contains(column) && m_Indicator[column] == false && qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance()/*非拖拽*/) { setSectionsClickable(false); QHeaderView::mouseReleaseEvent(event); setSectionsClickable(true); } QHeaderView::mouseReleaseEvent(event); ...
如上代码,m_Indicator结构中存储了咱们想要定制的是否容许排序的列,只须要对外暴露一个修改接口便可,代码是否是还很简单呢。
void QRowHeader::SetSortEnable(int logicalIndex, bool enable) { m_Indicator[logicalIndex] = enable; }
这样禁用某些列排序的功能就是实现了。
禁用某些列排序这个功能相对来讲好实现一些,毕竟重写的逻辑不是特别复杂,下面咱们来看下怎么修改排序交互逻辑。
二、排序交互修改
有了前面的问题处理思路,这个功能依然如此,咱们先跟Qt源码,看看已有的排序交互逻辑实现怎么实现的,而后在合理的实际去重置某些变量的值,达到重写交互逻辑。
博主这里跟踪完Qt默认的排序实现方式后,发现重写这个功能仍是有必定难度的,首先数据排序是一块,另外一块是一旦启用排序后,排序箭头的绘制这块也须要去重写。
什么意思呢?
Qt的排序规则一旦启用,排序的箭头就会被绘制,而且绘制箭头的逻辑还简单粗暴,不是升序就是降序。
且看以下Qt表头绘制源码
若是显示排序箭头而且是排序列,则须要绘制排序箭头,不是降序就是升序
我:我槽。。。什么鬼,就不能提供一个空的枚举吗?
void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { ... if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex) opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder) ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp; ... }
既然这条路子是走不通了,那么咱们只能取巧,换其余方式。
终于、皇天不负有心人被博主想到一个好办法,代码量依然仍是不多。
回到咱们最开始的需求,咱们其实就是想让第三次点击时,只是一个特殊的操做,而后把第四点击当作第一次单击便可。
有了这个想法后,那么就来干吧,既然仍是重写鼠标抬起函数,想尽一切办法监控连续的第三次单击,把他处理成非排序状态,而后在下一次单击时,走正常的排序逻辑。
void QRowHeader::mouseReleaseEvent(QMouseEvent * event) { ... QHeaderView::mouseReleaseEvent(event); column = logicalIndexAt(event->pos().x()); static bool nextNoSort = false; static int prevColumn = -1; if (nextNoSort && prevColumn == column && qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance()) { emit RestoreSort();//恢复默认排序 } if (nextNoSort != true && prevColumn == column && sectionsClickable() && sortIndicatorOrder() == Qt::DescendingOrder) { if (qAbs(event->x() - m_pPressPos.x()) < QApplication::startDragDistance()) { nextNoSort = true; prevColumn = column; } else { nextNoSort = false; } } else { if (nextNoSort && qAbs(event->x() - m_pPressPos.x()) >= QApplication::startDragDistance()) { nextNoSort = true; } else { nextNoSort = false; prevColumn = column; } } ... }
好了,代码以上。不过这里重点仍是要说下为何这么干!
首先须要调用父类的mouseReleaseEvent函数,不然拖拽会有问题,并且必须调用这个函数才可让内存数据正常。
而后咱们记录了一系列内存状态,判断是否是须要恢复排序状态,当条件知足时发出RestoreSort信号,外部程序只须要接收这个信号,而后恢复默认排序便可。
恢复默认排序
void QRowTable::RestoreSort() { m_pFilter->SetCompareType(QFilterModel::CT_NULL); m_pFilter->invalidate(); m_pHHeader->setSortIndicator(-1, Qt::DescendingOrder); }
4、相关文章
值得一看的优秀文章:
<br> <html> <div style='font-weight:600;'> 若是您以为文章不错,不妨给个<span style='font-size:24px;color:blue;'>打赏</span>,写做不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! </div> <center> <div> <table> <tr> <td><img src=https://www.cnblogs.com/images/cnblogs_com/swarmbees/1497876/o_weixin_reward.png border=0></td> <td><img src=https://www.cnblogs.com/images/cnblogs_com/swarmbees/1497876/o_zhifubao_reward.png border=0></td> </tr> </table> </div> </center> </html>
<br><br>
很重要--转载声明
-
本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 or Twowords
-
如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时经过修改本文达到有利于转载者的目的。
原文出处:https://www.cnblogs.com/swarmbees/p/11519796.html