TableView超多列的解决办法
问题描述
在QML中我们经常商用TableView来进行数据的展示。大部分情况下使用Qt Quick Controls 1自带的TableView是问题不大的。但在某些情况下则会有力不从心的感觉,比如表格的列可能有一百甚至数百列的时候就会出现刷新效率低下的问题。
查看TableView的源码你会发现这是TableView的实现是以行为基本单位,在行数很多时只会实现真正显示的那十几行的委托。所以在行数过多时问题也不大。
但在Qt Quick Controls 1中的TableView只针对行进行了优化,它实现时没有考虑列数过多的情况。当表格的列有300列时,哪怕只刷新表格显示的20行,也会有将近6000个对象进行绘制。
解决办法
对于这个问题,你可以将Qt Quick Controls 1的TableView源码分离出来,自己针对这一部分进行优化。但这个方法比较费力不讨好,出现新的bug的可能性更大。
索性Qt官方也知道自己的这个问题了,所以在后来增加了一个新的TableView。下面针对这个新的TableView说一下。
前提条件
在Qt 5.12的版本中官方增加了这个他们宣传更加高效快速的TableView。所以如果你的无法升级到Qt 5.12以上的版本,这篇文章对你意义不大可以右上角了。
新TableView的引用
众所周知Qt Quick Controls 1有很多问题,Qt官方处于种种原因又重复造了一次轮子这就是Qt Quick Controls 2。而这里介绍到的TableView也是Qt官方在5.12版本又造的一次轮子。所以在QML项目中如果不注意应用很容易混淆这两个控件。
- 使用之前的TableView一般是引用以下插件
import QtQuick.Controls 1.4
在Qt creator中是这些属性
- 而新版本的TableVew是来自以下插件
import QtQuick 2.12
在Qt creator中是这些属性
新TableView的效果
Qt官方给出了两个TableView的效果,其实我更愿意称之为Excel,其用法和我们想要的TableView效果差距还是很大的。
看到这个图大伙可能知道我为什么这么说了。因为这个Table没有表头没有列名……
新TableView的问题
新TableView是以单元格为基本单位进行绘制,也就是说它只会绘制你表格显示在界面中的数据。即时你有3000列x1000行,它也只会绘制你界面实际显示的6x20行。绘制对象少了不止一个量级。
所以在效率上确实不需要担心。本人实测300列插入10000行的时间也不到1ms。
-
但有利有弊,以单元格作为基本单位进行选择绘制的第一个问题就是新TableView没有行的概念!
这句话的意思不是没有行数这个属性了,在新TableView中还是有rows这个参数的,我说没有行是指不存在类型之前TableView的rowDelegate这种用法。 -
第二个问题就是新TableView不自带表头
所以得自己去处理列名、表头绘制…… -
第三个问题就是无法再通过role属性直接访问表格的值
自定义TableView
如果你看到这里还没有放弃看下去的想法,那看来也是被QML的这个问题逼得够呛。如果你没有更好的解决方案暂且看看我的例子,希望对你有所帮助。
代码我也传一份到CSDN,为了照顾部分没分的同学,我这里贴一些。写的时候部分地方用到了公司的代码所有进行了部分调整,颜色搭配需要下下来后再次调整。
- 自定义表头
新TableView没有表头只有我们自己来手动实现一个,这部分算最简单的。几十行代码也够用了。
一下是TableHead的代码
TableHeader.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Item{
id: header_horizontal
//暂存鼠标拖动的位置
property int posXTemp: 0
MouseArea{
anchors.fill: parent
onPressed: header_horizontal.posXTemp=mouseX;
onPositionChanged: {
if(table_view.contentX+(header_horizontal.posXTemp-mouseX)>0){
table_view.contentX+=(header_horizontal.posXTemp-mouseX);
}else{
table_view.contentX=0;
}
header_horizontal.posXTemp=mouseX;
}
}
Row {
id: header_horizontal_row
anchors.fill: parent
leftPadding: -table_view.contentX
clip: true
Repeater {
model: table_view.columns > 0 ? table_view.columns : 0
Rectangle {
id: header_horizontal_item
width: table_view.columnWidthProvider(index)+table_view.columnSpacing
height: parent.height
color: "red"//自己配色
border.width: 1
border.color: "#1a2b3c"
Label {
width:parent.width
height:control.horHeaderHeight
horizontalAlignment: Text.AlignHCenter
//anchors.fill: parent
text: _sourceModel.headerData(index,Qt.Horizontal)
}
Rectangle {
width: parent.width
height: filterMode*25
anchors.bottom: parent.bottom
color: "blue"
visible:height !== 0
TextInput{
anchors.fill: parent
onTextChanged:{
// console.log(text,index)
//设置过滤条件
_displayModel.setCondition(index,text)
table_view.forceLayout()
}
}
Behavior on height {
PropertyAnimation{
duration : 200 }
}
}
Rectangle{
width: 1
height: parent.height
anchors.right: parent.right
color: "black"
opacity: 0.5
}
MouseArea{
width: 3
height: parent.height
anchors.right: parent.right
cursorShape: Qt.SplitHCursor
onPressed: header_horizontal.posXTemp=mouseX;
onPositionChanged: {
if((header_horizontal_item.width-(header_horizontal.posXTemp-mouseX))>10){
header_horizontal_item.width-=(header_horizontal.posXTemp-mouseX);
}else{
header_horizontal_item.width=10;
}
header_horizontal.posXTemp=mouseX;
//改变某列的宽度
control._columnWidthArr[index]=(header_horizontal_item.width-table_view.columnSpacing);
//刷新布局,这样宽度才会改变
table_view.forceLayout();
}
}
}
}
}
}
TableScrollBar.qml
import QtQuick 2.12
import QtQuick.Controls 2.5
ScrollBar {
id:scroRoot
// policy: ScrollBar.AlwaysOn
contentItem: Rectangle{
visible: (scroRoot.size<1.0)
color: scrollBarColor
}
}
TableCell.qml
import QtQuick 2.12
import QtQuick.Controls 1