当前位置: 移动技术网 > IT编程>开发语言>C/C++ > QRowTable表格控件(五)-重写表头排序、支持第三次单击恢复默认排序

QRowTable表格控件(五)-重写表头排序、支持第三次单击恢复默认排序

2019年09月15日  | 移动技术网IT编程  | 我要评论

我就是社工库,ksdef,巫医格尔布尔

目录

原文链接:qrowtable表格控件(五)-重写表头排序、支持第三次单击恢复默认排序

一、原生表格

开发客户端程序的方式月来源多了,现在很流行的libcef、electron等等都可以作为快速开发客户端软件的方案,但是如果需要一个号的用户体验,还是离不开原生化的开发,虽然慢,但是性能好啊。

说到原生化开发,那对应的ui库相对较多,流行的就有qt、soui、duilib、还有老掉牙的mfc和其他一些第三方公司开源维护的directui库等等。网上找到一篇整理的文章,有兴趣的同学可以参考c++界面库

目前c++客户端使用最广泛的就是ui框架就是qt,它不仅包含了gui控件,更多的其实是一种解决方案,使用过qt的同学都比较清楚,qt的安装动态库有几十个之多,可是如果你只想使用qt的gui模块的话,就只需要包含3个动态库即可,他们分别是核心模块qtcore、gui模块qtgui和qtwidget。

当我们将qt作为我们的开发sdk时,大多数时候原生的控件+qss美化就可以完成我们的需求,然而总有一些特殊情况,比如产品经理脑残的时候、或者说是业务场景傻逼了,总是需要完成一些奇奇怪怪交互,那么我们就需要重写原生的控件实现方式。

今天就来说一个案例--表格控件列排序方式。

对于某一些特殊的场景下,我们的表格展示的数据可能需要排序,这样的表格控件qt已经给我们提供好了,只需要我们从写一些类和接口即可。前边已经写了4篇关于表格控件的功能,分别是qrowtable表格控件-支持hover整行、checked整行、指定列排序等qrowtable表格控件(二)-红涨绿跌qrowtable表格控件(三)-效率优化之-合理使用qstandarditemqrowtable表格控件(四)-效率优化之-优化数据源,感兴趣的同学可以去看看。

不幸的是qt自带的表格排序功能,即是我们冲写完所有接口依然不能满足负责的业务需求--表格表头连续3点三次是一个循环,什么意思呢?

传统表格排序

qt自带的表格排序行为是这样的,默认情况是不排序的,我们可以通过接口开启排序,或者通过接口设置不排序,当我们启用排序规则后,假设说我们的表格点击点击一下是降序,点击第二下就是升序,再次点击是又会恢复到降序规则,这样是不是还挺完美呢!

这个时候产品有话说了,点击第三次时,需要设置程序为不排序。

程序员:卧槽。。。。你说什么。。。。听不到。。。。

新的排序规则

在传统表格排序的基础上做一下调整

  1. 可以支持某些列不允许排序
  2. 3次连续单击为一个循环,也就是降序-升序-无序这样3个状态循环

不得不说产品的脑洞还是很大的。既然产品都说想要这个功能了,那么有时间还是得考虑下。跟产品沟通良久后,有了如下安排,虽然这个功能对用户来说不是一个特别需要的功能,但是当我们的软件功能稳定后,迭代没有那么着急的时候,是不是可以考虑研究下这个而功能呢。

然后也就有了本篇文章

虽然重写了qt本身的逻辑,没想到还是可以实现的!!!

二、效果展示

按照惯例先上图,看看是不是同学们想要的功能。

三、实现方式

新的表格排序有2个点需要我们去思考,分别是某些列排序、排序交互修改,下面我们分开来去实现

1、排序列定制

qt默认提供了可排序接口,但是开启后我们所有的列都支持排序了,这个时候我们就需要研究qt的源码,看看qt的排序是怎么触发的,然后在合理的时机去加上我们不支持排序的逻辑

博主这里找到的做法是重写qhaderview这个类,并重写实现了鼠标按下并抬起的接口,在这个接口中判断我们业务层是不是允许排序。

重写后的逻辑是这样的

  1. 如果不允许排序,我们先调用qt原有的接口禁用所有列排序功能

  2. 调用父类的鼠标抬起函数

  3. 如果不允许排序,需要调用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;
}

这样禁用某些列排序的功能就是实现了。

禁用某些列排序这个功能相对来说好实现一些,毕竟重写的逻辑不是特别复杂,下面我们来看下怎么修改排序交互逻辑。

2、排序交互修改

有了前面的问题处理思路,这个功能依然如此,我们先跟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);
}

四、相关文章

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

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

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

  4. 超级实用的属性浏览器控件--qttreepropertybrowser

  5. qt之表格控件蚂蚁线

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

  7. qrowtable表格控件(二)-红涨绿跌

  8. qrowtable表格控件(三)-效率优化之-合理使用qstandarditem

  9. qrowtable表格控件(四)-效率优化之-优化数据源

  10. c++界面库


值得一看的优秀文章:

  1. qt定制控件列表
  2. 牛逼哄哄的qt库





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














很重要--转载声明

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

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


如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网