怎样优化QTableView的性能

我是题主,今天刚解决了此问题,来回答下我的解决方案正如题目里所说,我自己写的一个轻量级的demo,数据刷新几乎无延迟,和实际程序中严重不符。经过各种profile,最终定位了问题原因——VerticalHeader的resize。实际开发的这个程序,由于数据每次请求都是不同的,header的内容也会不同,所以更新数据后需要对其进行resize。而单纯的把resizeMode设置为resizeToContents效果并不好,只会在第一次更新数据时生效。之后更新数据后,不管是调用endResetModel()还是headerDataChanged(),QTableView都不会刷新verticalHeader的宽度,只会刷新其中的数据。如果要刷新verticalHeader的宽度,要么重设model,要么把QTableView给hide()再show()出来,调用update()或者repaint()都不行。然而,只要resizeMode是QHeaderView::ResizeToContents,那么采用上述两种方法触发全局重绘时,QTableView都会请求表头中每一个section的数据,并且用QFontMetrics计算宽度,故而数据量庞大时,这个计算耗时长到无法容忍。所以,在数据量非常庞大时,使用自适应的resize是不可行的。——————————————————————————于是我们尝试了以下两种解决方案1、手动设置定长的表头数据。比如表头可能出现的数据是1到100000,那么我们就以最长的为标准,不够长度的补空格。这样不用需要设置自适应,表格刷新和切换可以瞬间完成。但代价是表头很丑,在数据小时有大片空白2、使用当前最大的表头数据,仅对该数据用QFontMetrics计算宽度,然后对表头设置fixedWidth()。这样理论可行,然而实际很丑陋,调整宽度后多出来的部分只有QWidget底色,文本信息并没有绘制上去,导致表头文本显示不完全,且表头效果绘制错误。然后尝试搜索了"QTableView VerticalHeader width"关键字之后,在Qt论坛搜到一篇帖子,里面给了一个脑洞清奇的解法——设置表头宽度后,将首列宽度设置为0,再重置,即代码如下:ui-\u0026gt;tableView-\u0026gt;verticalHeader()-\u0026gt;setFixedWidth(width);width = ui-\u0026gt;tableView-\u0026gt;columnWidth(0);ui-\u0026gt;tableView-\u0026gt;setColumnWidth(0, 0);ui-\u0026gt;tableView-\u0026gt;setColumnWidth(0, width);上述代码,会导致表格布局改变,从而触发表格的全局重绘,在这次重绘里,重设宽度过后的表头也能正常显示了。由于所有column和表头都没有设置自适应,所以这个重绘效率很高。最后profile结果如下: - 在设置自适应后,表格刷新耗时10ms内。但若要重新适配表头,则需要耗时10s左右。 - 关闭自适应,通过手动设置fixedWidth方式适配表头,数据刷新加适配表头,总体耗时不超过20ms。——————————————————————————结论resizeToContents这个尺寸自适应模式,不管是对于column,还是对于header,都慎用。该函数会遍历该contents内所有数据,逐一通过QFontMetrics计算尺寸,这个耗时在数据量到达一定量级的情况下,高到无法接受。本来,使用view-model-delegate机制就是为了规避性能问题,在这套机制下,动态更新数据非常灵活,并且UI只会绘制显示的那一部分数据,所以理论上不管数据量有多大,界面耗时都是常量级的。但也有一些例外,这些情况下依旧会遍历所有数据,典型的就是resizeToContents。真如题主这样,遇到非要自适应不可的场景,也最好根据实际场合中的数据特点,手动进行适配
■网友
赞一下。我做过类似的表格,用的就是QML的TableView,不过数据量不是太大,遇到的主要都是功能问题。在这总结分享一下,做的不好轻喷。
先上个效果图,好让大家有个直观的感受:

怎样优化QTableView的性能


推荐阅读