在qt中构建界面时经常会对多个数据进行排列显示,可以使用qml提供的ListView组件来快速的构建一个列表模型来进行列表内容的分组显示;
通常的步骤是定义一个简单的ListView列表。创建一个Model并填入数据到其中;
Rectangle {
id:rootRect;
width:600;
height:200;
color:"grey";
ListView {
id:listView;
width:parent.width;
height:parent.height;
clip:true; //对超出划定边界的数据进行裁剪
delegate:modelItem; //自定义列表内容的组件,属性是Component
//构建一个Model,也可以直接引入c++中的创建的model 运行程序可已看到生成了一个包含name,age,Heigth的列表
model:ListModel {
id: listModel;
ListElement {
name:"jack";
age: "22";
Height: "188cm"
}
ListElement {
name:"mark";
age:"19";
Height:"178cm";
}
ListElement {
name:"zhangsan";
age:"17";
Height:"177cm";
}
ListElement {
name:"lisi";
age:"27";
Height:"167cm";
}
ListElement {
name:"xiaoxiao";
age:"25";
Height:"18";
}
}
}
Component {
id:modelItem;
Rectangle {
width:parent.width;
height:40;
color: "grey"
Row {
width:0.9*parent.width;
anchors.left: parent.left;
anchors.leftMargin: 0.1*parent.width;
height:parent.height;
Label {
text: name;
font.pixelSize: 20;
width: 0.3*parent.width;
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: age;
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: Height;
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
}
}
}
}
以上的内容在qt运行显示的是一个基础的列表,但是一眼望去并不明确每一项的具体含义, 这样在一些使用过程中很不方便:具体的显示效果如下:
可以通过鼠标移动或者滚轮滑动查看列表的显示,但是对每一项的含义不是那么的直观,也有一种方法就是直接在model也就是列表的index为1的时候添加每一列的名称进去,显示的时候可以看到每一列的名称,具体代码如下,只需在model的第一列添加如下代码到最前面:(修改后的model如下)
model:ListModel {
id: listModel;
ListElement {
name:"name";
age:"age";
Height:"height";
}
ListElement {
name:"jack";
age: "22";
Height: "188cm"
}
ListElement {
name:"mark";
age:"19";
Height:"178cm";
}
ListElement {
name:"zhangsan";
age:"17";
Height:"177cm";
}
ListElement {
name:"lisi";
age:"27";
Height:"167cm";
}
ListElement {
name:"xiaoxiao";
age:"25";
Height:"181cm";
}
ListElement {
name:"huahua";
age:"38";
Height:"188cm"
}
}
效果展示:
可以看到第一行有显示每一列数据的名字了,但是因为设置的字体显示与后面一致(可以单独对某一个index的item设置不同的参数来突出显示,这里不做过多说明),而且会随着滑动,而且数据多了会滑动消失,所以不推荐使用;
在qml中,可以ListView的特性创建一个列表头,显示每一项的具体含义;表头header的属性和delegate一样也是Component;通过自定义表头的组件显示到列表最上面;
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.4
Window {
id: window
width: 640
height: 200
visible: true
title: qsTr("Hello World")
//qml ListView组件
/*
定义一个简单的ListView列表,并创建一个Model填入数据,运行程序可已看到生成了一个包含name,age,Heigth但是一眼望去并不明确每一项的具体含义;
利用ListView的特性创建一个列表头,显示每一项的具体含义;表头header的属性和delegate一样也是Component;
*/
Rectangle {
id:rootRect
width:parent.width;
height:parent.height;
color: "darkgrey";
ListView {
id:listView;
width:parent.width;
height:parent.height;
clip: true; //超出边界的数据进行裁剪
delegate:modelItem;
header:headerView;//只构建表头上滑动时表头也会跟随上滑动消失
headerPositioning: ListView.OverlayHeader;//枚举类型
/*
ListView.OverlayHeader: 向上滑动直接覆盖表头
ListView.InlineHeader:表头和内容是放置在一起的,移动也是一起移动,默认设置此属性;
ListView.PullBackHeader:表头和内容是可以分开,向上滑动会顶上去看不见
*/
//构建一个Model
model:ListModel {
id: listModel;
ListElement {
name:"jack";
age: "22";
Height: "188cm"
}
ListElement {
name:"mark";
age:"19";
Height:"178cm";
}
ListElement {
name:"zhangsan";
age:"17";
Height:"177cm";
}
ListElement {
name:"lisi";
age:"27";
Height:"167cm";
}
ListElement {
name:"xiaoxiao";
age:"25";
Height:"18";
}
}
}
Component {
id:headerView;
Rectangle {
width:parent.width;
height: 40;
color: "lightgrey";
z:2;//将表头的z坐标设置在上层,表头在设置属性为overlayHeader时就不会随滑动而消失,始终显示在最上面
Row {
width: 0.9*parent.width;
height: parent.height;
anchors.left: parent.left;
anchors.leftMargin: 0.1*parent.width;
Label {
text: "name";
font.pixelSize: 20;
width: 0.3*parent.width;
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: "age";
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: "Height";
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
}
}
}
Component {
id:modelItem;
Rectangle {
width:parent.width;
height:40;
color: "grey"
Row {
width:0.9*parent.width;
anchors.left: parent.left;
anchors.leftMargin: 0.1*parent.width;
height:parent.height;
Label {
text: name;
font.pixelSize: 20;
width: 0.3*parent.width;
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: age;
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
Label {
text: Height;
font.pixelSize: 20;
width: 0.3*parent.width
anchors.verticalCenter: parent.verticalCenter;
verticalAlignment: Text.AlignHCenter;
}
}
}
}
}
}
如果表头还是会随着滑动消失,可以设置组件的z轴,让该组件显示在最上层,达到表头一直显示的效果;特别要注意的是需要设置ListView的headerPositioning的属性为ListView.OverlayHeader这个类型(三个类型的描述在代码里有注释),这个是向上滑动覆盖表头,但是因为表头的z轴设置的是最上层,所以并不会被覆盖,以此达到表头显示的效果。
以上的header添加后就可以在显示一个带表头的列表,并且列表滑动表头不会随着列表滑动,始终显示在最上方。实现效果显示如下:
可以看到表头一直显示到最上方,且不会随滑动消失。
还有一个问题就是一个点击穿透的问题,上滑后点击表头会触发列表内容的点击,如果有监控对列表的点击操作时点击表头就会造成误操作,这里就需要做一个放穿透效果,即在表头的组件中加上以下代码:
MouseArea {
anchors.fill: parent;
onPressed: {
mouse.accepted = true;
}
}
如上所述。