欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

QML学习摘录 06 - 模型/视图/代理

程序员文章站 2022-05-31 12:04:41
...

QML中模型/视图/代理

模型Model指的是数据;视图View指显示,可视化的处理;Model-View概念的提出是为了实现数据与显示的分离。代理Delegate将模型和视图链接起来。
例如电话簿程序中,电话簿中的数据(名字,号码等)由Model提供,View中的每个数据都是Delegate来实现可视化,View的作用是排列这些Delegate提供的项。
QML学习摘录 06 - 模型/视图/代理

1、基础模型

模型/视图最基本的用法是Repeater元素。它被用作实例化一组元素项。
下面的例子,将链表模型ListModel中的每个元素绑定到属性上,每个元素中的属性链接到repeater实例化的子项上(name属性被链接到text)。

import QtQuick 2.3
Column {
    y:5
    spacing: 2
    ListModel {
        id: listModel
        ListElement {name: "Apple";cost: 2.45}
        ListElement {name: "Orange";cost: 3.25}
        ListElement {name: "Banana";cost: 1.95}
    }
    Repeater {
        model: listModel
        Rectangle {
            width: 100;height: 20
            radius: 3
            color: "lightblue"
            anchors.horizontalCenter: parent.horizontalCenter
            Text {
                anchors.centerIn: parent
                text: index+":"+name
            }
        }
    }
}

运行结果:
QML学习摘录 06 - 模型/视图/代理

2、动态视图

Repeater元素适合有限的静态数据,但是在真正使⽤时,模型通常更加复杂和庞⼤,我们需要⼀个更加智能的解决⽅案。QtQuick提供了ListView和GridView元素,这两个都是基于Flickable(可滑动)区域的元素,因此⽤户可以放⼊更⼤的数据。同时,它们限制了同时实例化的代理数量。对于⼀个⼤型的模型,这意味着在同⼀个场景下只会加载有限的元素。

2.1 ListView

ListView与Repeater元素相似,它使⽤了⼀个Model,使⽤Delegate来实例化,并且在两个delegate之间能够设置间隔sapcing。下⾯的列表显⽰了怎样设置⼀个简单的链表。

import QtQuick 2.0

Rectangle {
    //x:10;
    y: 5

    ListView {
        id: view
        anchors.fill: parent
        anchors.margins: 10
        clip: true
        model: 100
        delegate: numberDelegate
        spacing: 5
        boundsBehavior: Flickable.DragOverBounds //末尾行为
        snapMode: ListView.SnapToItem //限制一个视图内元素的停止位置
        //orientation: ListView.Horizontal//方向
        highlight: hightlightComponent
        highlightFollowsCurrentItem: true
        highlightRangeMode: ListView.NoHighlightRange //控制高亮如何显示
        highlightMoveDuration: 500
        focus: true

        header: header 
        footer: footer
    }
    Component {//页脚
        id: footer
        Rectangle {
            width: view.width
            height: 20
            radius: 3
            color: "gray"
            Text {anchors.centerIn: parent;text: "footer"}
        }
    }
    Component {//页眉
        id: header
        Rectangle {
            width: view.width
            height: 20
            radius: 3
            color: "gray"
            Text {anchors.centerIn: parent;text: "header"}
        }
    }

    Component {
        id: numberDelegate
        Item {
            width: view.width
            height: 30
            Text {
                anchors.centerIn: parent
                text: index
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    view.currentIndex = index
                }
            }
        }
    }
    Component {//高亮
        id: hightlightComponent
        Rectangle {
            width: view.width
            radius: 3
            color: "yellow"
        }
    }
}

运行预览:
QML学习摘录 06 - 模型/视图/代理

2.2 GridView

使⽤网格视图(GridView)与使⽤链表视图(ListView)的⽅式⾮常类似。真正不同的地⽅是GridView使⽤了⼀个⼆维数组来存放元素,⽽ListView是使⽤的线性链表来存放元素。GridView不依赖于元素间隔和⼤⼩来配置元素。它使⽤单元宽度(cellWidth)与单元⾼度(cellHeight)属性来控制数组内的⼆维元素的内容。每个元素从左上⾓开始依次放⼊单元格。

import QtQuick 2.0

Rectangle {
    y: 5
    GridView {
        anchors.fill: parent
        anchors.margins: 20
        clip: true
        model: 100
        cellWidth: 45;cellHeight: 45
        delegate: numberDelegate
        flow:GridView.RightToLeft;//方向 
    }
    Component {
        id: numberDelegate
        Rectangle {
            width: 40;height: 40
            color: "lightGreen"
            Text {anchors.centerIn: parent;font.pixelSize: 10;text:index}
        }
    }
}

运行预览:
QML学习摘录 06 - 模型/视图/代理

3.代理

当使⽤模型与视图来⾃定义⽤户界⾯时,代理在创建显⽰时扮演了⼤量的⾓⾊。在模型中的每个元素通过代理来实现可视化,⽤户真实可见的是这些代理元素。每个代理访问到索引号或者绑定的属性,⼀些是来⾃数据模型,⼀些来⾃视图。来⾃模型的数据将会通过属性传递到代理。来⾃视图的数据将会通过属性传递视图中与代理相关的状态信息。
在下面的例子中我们可以看到代理的背景色color与视图的isCurrentItem 属性绑定(01)。

动态增加/删除元素

在某些情况下,视图中的显⽰内容会随着时间⽽改变。由于模型数据的改变,元素会添加或者移除。在这些情况下,⼀个⽐较好的做法是使⽤可视化队列给⽤户⼀个⽅向的感觉来帮助⽤户知道哪些数据被加⼊或者移除。
为了⽅便使⽤,QML视图为每个代理绑定了两个信号,onAddonRemove。下⾯这个例⼦演⽰了如何动态填充⼀个GridModel。在屏幕下⽅,有⼀个添加新元素的按钮。当点击它时,会调⽤模型的append⽅法来添加⼀个新的元素。这个操作会触发视图创建⼀个新的代理,并发送GridView.onAdd信号。SequentialAnimation队列动画与这个信号连接绑定,使⽤代理的scale属性来放⼤视图元素(02)。

import QtQuick 2.0
Rectangle {
    y: 5
    ListModel{
        id:listModel
        ListElement{number :0}
        ListElement{number :1}
        ListElement{number :2}
        ListElement{number :3}
        ListElement{number :4}
    }
    GridView {
        id: view
        anchors.fill: parent
        anchors.margins: 20
        clip: true

        model: listModel

        delegate: numberDelegate
        focus: true
    }

    Rectangle{
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        anchors.margins: 20
        height: 40
        color:"lightblue"
        border.color: Qt.lighter(color,1.1)
        Text{anchors.fill:parent;text:"add item"}
        MouseArea{
            anchors.fill: parent
            onClicked: {listModel.append({"number": listModel.count });}
        }
    }
    Component {
        id: numberDelegate
        Rectangle {
            id:wrapper
            width: 40;height: 40
            color: GridView.isCurrentItem ? "red" : "blue"// 01. color与视图的属性绑定
            Text {
                anchors.centerIn: parent
                font.pixelSize: 14;color:"white"
                text: number
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                view.currentIndex = index  
                }
            }
            GridView.onAdd:SequentialAnimation{//02.QML为代理绑定的信号,当元素被增加时发送该信号
                NumberAnimation{target: wrapper;property:"scale";from:0;to:1;duration: 250}
            }
        }
    }
}

运行预览:
QML学习摘录 06 - 模型/视图/代理

更多进阶用法参考原文网址:http://qmlbook.github.io/en/ch06/index.html#advanced-techniques