【QT】QML—— ListView添加固定表头的方法

  • Post author:
  • Post category:其他


在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;
    }
}

如上所述。



版权声明:本文为weixin_45054387原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。