QML学习摘录 06 - 模型/视图/代理
QML中模型/视图/代理
模型Model指的是数据;视图View指显示,可视化的处理;Model-View概念的提出是为了实现数据与显示的分离。代理Delegate将模型和视图链接起来。
例如电话簿程序中,电话簿中的数据(名字,号码等)由Model提供,View中的每个数据都是Delegate来实现可视化,View的作用是排列这些Delegate提供的项。
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
}
}
}
}
运行结果:
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"
}
}
}
运行预览:
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}
}
}
}
运行预览:
3.代理
当使⽤模型与视图来⾃定义⽤户界⾯时,代理在创建显⽰时扮演了⼤量的⾓⾊。在模型中的每个元素通过代理来实现可视化,⽤户真实可见的是这些代理元素。每个代理访问到索引号或者绑定的属性,⼀些是来⾃数据模型,⼀些来⾃视图。来⾃模型的数据将会通过属性传递到代理。来⾃视图的数据将会通过属性传递视图中与代理相关的状态信息。
在下面的例子中我们可以看到代理的背景色color与视图的isCurrentItem 属性绑定(01)。
动态增加/删除元素
在某些情况下,视图中的显⽰内容会随着时间⽽改变。由于模型数据的改变,元素会添加或者移除。在这些情况下,⼀个⽐较好的做法是使⽤可视化队列给⽤户⼀个⽅向的感觉来帮助⽤户知道哪些数据被加⼊或者移除。
为了⽅便使⽤,QML视图为每个代理绑定了两个信号,onAdd和onRemove。下⾯这个例⼦演⽰了如何动态填充⼀个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}
}
}
}
}
运行预览:
更多进阶用法参考原文网址:http://qmlbook.github.io/en/ch06/index.html#advanced-techniques