由于最近在项目中需要加载几GB的文件,并且需要在QTableWidget中进行显示;粗略估计可能得有几千万行,如果使用常规的方法,直接在QTableWidget中进行全部显示,会比较卡。所以查找相关资料,最终想到了一个比较巧妙的实现方法。
基本思路是:QTablewidget中每一次可见的行数基本上只有几十行,即便全屏显示,最多也就100行(应该远远达不到),而电脑的性能刷新100行的数据基本上也是毫秒级别的(没有实测),所以,只需要每一次QTableWidget的滚动条变化时,重新把可见的数据填充进去就可。
代码实现:
1、创建CacheTableWidget类,管理QTableWidget和自定义的QScrollBar对象,目的是要实现上述功能,需要隐藏QTableWidget自身的滚动条,利用自己创建的QScrollBar对象实现QTableWidget的滚动效果。
m_tw:填充数据的QTableWidget
m_vBar:模拟QTableWidget的滚动条
m_viewRow:每次视图刷新时,QTableWidget可以显示的行数
verticalValueChanged:自定义滚动条变化时,通知上层更新表格数据
此处隐藏掉QTableWidget的滚动条,并设置样式,主要目的是为了让自定义的滚动条看起来像QTableWidget原生的效果;
另外:QTableWidget的监听事件,必须监听QTableWidget的viewport视图,否则无法捕获QTableWidget的鼠标事件;
此处将QTableWidget和QScrollBar通过布局拼装在一起,设置的样式是为了让QTableWidget和QScrollBar看起来是一体的。
重新实现resizeEvent事件,捕获窗体变化时,重新计算QTableWidget可显示的行数,并通知上层刷新数据;另外qCeil函数导致QTableWidget会多刷新一行数据,可能会导致最后一行数据无法显示上有问题,可以改为qFloor函数;
捕获鼠标滚动事件,模拟鼠标滚动效果;
上层更新表格数据的方法就比较简单,每一次滚动条变化时,清空QTableWidget内容,以QScrollBar的值为索引刷新QTableWidget的数据;
上层使用时,需要调用setMaxLine函数,设置m_vbar的最大值,需要和自定义的结果集对应,此处为list对象;
注:addItem函数为自定义的QTableWidget添加一行的方法,此处报错仅仅只是为了演示,实际上会根据文件格式,定义自己的数据结构,此处用QStringList代替,所以会有函数不匹配的问题;
总结:
1、最开始想到的办法其实是通过分页的形式进行显示,即将数据按100行进行分页,如1、2、3、4、5、6...,QTableWidget每次加载3页的数据,即QTableWidget每次加载300行数据,当其滚动条落在第3页时,将2页的数据插入到前100行,第4页数据追加到200~300行;当滚动条由第3页滚动到第4页数据时,将之前的第2页数据删除,将第5页的数据追加到200~300行,即让QTableWidget滚动条的值始终落在100~200行之间,每次跳页时动态调整一次,这种方法调试了很长时间,始终无法处理好QTableWidget的滚动条和自定义滚动条之间的关系,实现的效果一直不好后续就放弃了。
2、增加分页按钮,即增加上一页、下一页按钮,每次通过点击按钮切换数据。由于没有现成的库,还需要重新调整按钮样式及布局,所以此作为备选。
3、后续想到的办法就是QTableWidget每一次可见的数据只有几行,每次只刷新这几行的数据应该会非常快,所以进行尝试,发现可行。
4、关于大文件数据读取这块,目前采用的方式还是单线程读取,后续可能还得改进,目前想到的方法有几种:a.将大文件进行分割,如1GB的文件,分割为5份,启用5个线程读取,最后进行数据合并。b.通过map文件映射的方法,读取。c.延时读取,先读取200行,QTableWidget显示到第100行时,在读取100行缓存等,可以灵活利用seek函数。
效果截图: