天天看点

QtQuick 中的模型视图代理

QtQuick 中的模型视图代理      
//对于开发用户界面,最重要的一方面是保持数据与可视化的分离。      
//在QML中,model与view通过delegate连接起来。model提供数据,对于每个数据项,可能有多个值;显示在view中      
//的每项数据都是通过代理来实现可视化;view的任务是排列这些delegate.      
* 最基本的分离数据与显示的方法是使用Repeater元素,它被用于实例化一组元素项,并且很容易与一个用于填充用户      
界面的定位器相结合。      
//实现举例,repeater元素用于实现子元素的标号      
import QtQuick 2.0      
Column{      
spacing: 2      
Repeater{      
model: 10      
Rectangle{      
width: 100      
height: 20      
radius: 3      
color: "lightBlue"      
Text{      
anchors.centerIn: parent      
text: index      
}      
}      
}      
}      
//运行效果:      
QtQuick 中的模型视图代理
//借助JavaScript中的序列:      
import QtQuick 2.0      
Column{      
spacing: 2      
Repeater{      
model: ["Enterprise","Colombia","Challenger","Discovery","Endeavour","Atlantis"];      
Rectangle{      
width: 100      
height: 20      
radius: 3      
color: "lightBlue"      
Text{      
anchors.centerIn: parent      
text: index + ": " + modelData      
}      
}      
}      
}      
//运行效果:      
QtQuick 中的模型视图代理
//每个元素都提供了一个名字和一个元素      
import QtQuick 2.0      
Column{      
spacing: 2      
Repeater{      
model: ListModel{      
ListElement{ name: "Mercury"; surfaceColor: "gray" }      
ListElement{ name: "Venus"; surfaceColor: "yellow" }      
ListElement{ name: "Earth"; surfaceColor: "blue" }      
ListElement{ name: "Mars"; surfaceColor: "orange" }      
ListElement{ name: "Jupiter"; surfaceColor: "orange" }      
ListElement{ name: "Saturn"; surfaceColor: "yellow" }      
ListElement{ name: "Uranus"; surfaceColor: "lightBlue" }      
ListElement{ name: "Neptune"; surfaceColor: "lightBlue" }      
}      
Rectangle{      
width: 100      
height: 20      
radius: 3      
color: "lightBlue"      
Text{      
anchors.centerIn: parent      
text: name      
}      
Rectangle{  //圆      
anchors.left: parent.left      
anchors.verticalCenter: parent.verticalCenter      
anchors.leftMargin: 2      
width: 16      
height: 16      
radius: 8      
border.color: "black"      
border.width: 1      
color: surfaceColor      
}      
}      
}      
//运行效果:      
QtQuick 中的模型视图代理
import QtQuick 2.0      
Column{      
spacing: 2      
Repeater{      
model: 10      
Rectangle{      
width: 100      
height: 20      
radius: 3      
color: "lightBlue"      
Text{      
anchors.centerIn: parent      
text: index      
}      
}      
}      
}      
//repeater的内容的每个子项实例化时绑定了默认的属性delegate,运行效果同第一段代码      
/*****************************************************************************************************/      
动态视图:      
//Repeater元素适合有限的静态数据,但在真正使用时,模型通常复杂庞大。QtQuick提供了ListView和GridView元素,      
//这两个都是基于可滑动区域的元素,用户可放入更大的数据。      
//链表视图:      
import QtQuick 2.0      
Rectangle{      
width: 80      
height: 300      
color: "white"      
ListView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true;     //显示超过parent尺寸时,不显示      
model: 100      
delegate: numberDelegate      
spacing: 5      
}      
Component{      
id: numberDelegate      
rectangle{      
width: 40      
height: 40      
color: "lightGreen"      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text: index      
}      
}      
}      
}      
//视图末尾的行为是由boundsBehavior属性控制的,这是一个枚举值。Flickable.DragAndOvershootBounds默认模式下,      
//内容到达最后会反弹回去;视图可通过边界线来拖拽和翻阅:Flickable.StopAtBounds,视图将不可移到边界线外;      
//可以将视图拖拽到它的边界线外,但在边界线上翻阅将无效:Flickable.DragOverBounds      
使用snapMode属性可以限制一个视图内元素的停止位置。默认是ListView.NoSnap,允许视图内元素在任何位置停止。      
ListView.SnapToItem:视图顶部将会与元素对象的顶部对齐排列。ListView.SnapOneItem:当鼠标或触摸释放时,视图会停止在第一个可见元素      
/********************************************************************************************************************************************/      
方向:      
//默认的链表视图只提供了一个垂直方向的滚动条,链表视图的方向由orientation控制,ListView.Vertical,ListView.Horizontal      
//水平链表简例:      
import QtQuick 2.0      
Rectangle{      
width: 480      
height: 80      
color: "white"      
ListView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true      
model: 100      
orientation: ListView.Horizontal      
delegate: numberDalegate      
spacing: 5      
}      
Component{      
id: numberDelegate      
Rectangle{      
width: 40      
height: 40      
color: "lightGreen"      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text.index      
}      
}      
}      
}      
//可以通过设置layoutDirection属性来控制元素顺序方向,可以被设置为Qt.LeftToRight 或 Qt.RightToLeft      
/*****************************************************************************************************/      
键盘导航和高亮:      
当使用基于触摸方式的链表视图时,默认提供的视图已经足够使用。在使用键盘选择一个元素时,需要有标识当前选中元素      
的机制。在QML中,这被叫做高亮。      
import QtQuick 2.0      
Rectangle{      
width: 240      
height: 300      
color: "white"      
ListView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true      
model: 100      
delegate: numberDelegate      
spacing: 5      
highlight: highlightComponent   //指出使用的高亮代理元素      
focus: true      
}      
Component{      
id: hightlightComponent      
Rectangle{      
width: ListView.view.width      
color: "lightGreen"      
}      
}      
Component{      
id: numberDelegate      
Item{      
width: 40      
height: 40      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text:index      
}      
}      
}      
}      
//运行结果:      
QtQuick 中的模型视图代理
highlightRangeMode控制了高亮如何影响视图中当前的显示:      
默认设置ListView.NoHightlightRange意味着高亮与视图中元素的距离不相关      
ListView.StrictlyEnforceRange确保了高亮始终可见      
ListView.ApplyRange在需要的情况下高亮代理允许移出当前视图      
默认配置下,视图负责高亮移动到指定位置,移动的速度和事件能够被改变:      
highlightMoveSpeed, highlightMoveDuration,      
highlightResizeSpeed, highlightResizeDuration      
默认速度:400像素,动作持续时间-1,若速度和持续时间都被设置,采用速度快的完成      
为了更加详细的控制高亮的移动,highlightFollowCurrentItem属性设置为false,表示视图      
不再负责高亮代理的移动,取而代之的是通过一个Behavior或者一个动画来控制它。      
/* 下面例子中,高亮代理的y坐标属性与ListView.view.currentItem.y属性绑定,确保了高亮始终跟随当前元素。      
然而,我们没有让视图来移动这个高亮代理,所以我们需控制这个元素如何移动,通过Behavior on y完成 */      
Component{      
id: highlightComponent      
Item{      
width: ListView.view.width      
height: ListView.view.currentItem.height      
y: ListView.view.currentItem.y      
Behavior on y{      
SequentialAnimation{      
PropertyAnimation{      
target: highlightRectangle      
property: "opacity"      
to: 0; duration: 200      
}      
NumberAnimation{ duration: 1 } //y发生变化,更该当前项的y值      
PropertyAnimation{      
target: highlightRectangle      
property: "opacity"      
to: 1; duration: 200      
}      
}      
}      
Rectangle{      
id: highlightRectangle      
anchors.fill: parent      
color: "lightGreen"      
}      
}      
}      
/*****************************************************************************************************/      
页眉和页脚:      
import QtQuick 2.0      
Rectangle{      
width: 80      
height: 300      
color: "white"      
ListView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true      
model: 4      
delegate: numberDelegate      
spacing: 5      
header: headerComponent     //页眉      
footer: footerComponent     //页脚      
}      
Component{      
id: headerComponent      
Rectangle{      
width: 40      
height: 20      
color: "yellow"      
}      
}      
Component{      
id: footerComponent      
Rectangle{      
width: 40      
height: 20      
color: "red"      
}      
}      
Component{      
id: numberDelegate      
Rectangle{      
width: 40      
height: 40      
color: "lightGreen"      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text: index      
}      
}      
}      
}      
//页眉页脚不遵循间隔属性,它们被直接放在链表元素之上或之下。页眉页脚的间隔必须通过页眉页脚元素自己设置      
/************************************************************************************************************************/      
网格视图:      
网格视图(GridView)不依赖与元素间隔和大小来配置元素。它使用单元宽度(cellWidth)和单元高度(cellHeight)      
来控制数组内二维元素的内容,每个元素从左上角开始一次放入单元格。      
#import QtQuick 2.0      
Rectangle{      
width: 240      
height: 300      
color: "white"      
GridView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true      
model: 100      
cellWidth: 45  //设置单元宽度      
cellHeight: 45   //设置单元高度      
delegate: numberDelegate      
}      
Component{      
id: numberDelegate      
Rectangle{      
width: 40      
height: 40      
color: "lightGreen"      
Text{      
anchors.centerIn: parent      
font.pixSize: 10      
text: index      
}      
}      
}      
}      
GridView也包含了页眉和页脚,也可以使用高亮代理并支持捕捉模式(snap)。它也可以使用不同的方向(orientation)      
与定向(direction)来定位。      
定向使用flow属性来控制,可被设置为GridView.LeftToRight, GridView.TopToBottom      
layoutDirection属性和flow属性能够适配网络从左到右或者从右到左      
/***********************************************************************************************************/      
代理(Delegate)      
当使用模型与视图来自定义用户界面时,代理在创建显示时扮演了大量的角色。模型中的每个元素通过代理来实现      
可视化,用户真实可见的是这些代理元素。      
每个代理访问的索引号或者绑定的属性,一些是来自数据模型,一些来自视图。来自数据的数据将会通过属性传递到代理,      
来自视图的数据将会通过属性传递视图中与代理相关的状态信息。      
通常使用的视图绑定属性是ListView.isCurrentItem和ListView.view.通过访问视图,可以创建可复用的代理,这些      
代理在被包含时会自动匹配视图的大小。      
import QtQuick 2.0      
Rectangle{      
width: 120      
height: 300      
color: "white"      
ListView{      
anchors.fill: parent      
anchors.margins: 20      
clip: true      
model: 100      
delegate: numberDelegate      
spacing: 5      
focus: true      
}      
Component{      
id: numberDelegate      
Rectangle{      
width: ListView.view.width   //代理的宽度和视图的宽度绑定      
height: 40      
color: ListView.isCurrentItem ? "gray" : "lightGray" //代理的背景颜色依赖于绑定的属性      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text.index      
}      
}      
}      
}      
如果在模型中的每个元素与一个动作相关,例如作用于一个元素时,这个功能是代理完成的。这是由事件管理分配给视图的,      
这个操作控制了视图中元素的导航,代理控制了特定元素上的动作。      
最基础的方法是在每个代理中创建一个MouseArea并且响应OnClicked信号。      
/*******************************************************************************************************/      
动画添加与移除元素:      
import QtQuick 2.0      
Rectangle{      
width: 480      
height: 300      
color: "white"      
ListModel{      
id: theModel      
ListElement{ number: 0 }      
ListElement{ number: 1 }      
ListElement{ number: 2 }      
ListElement{ number: 3 }      
ListElement{ number: 4 }      
ListElement{ number: 5 }      
ListElement{ number: 6 }      
ListElement{ number: 7 }      
ListElement{ number: 8 }      
ListElement{ number: 9 }      
}      
Rectangle{      
anchors.left: parent.left      
anchors.right: parent.right      
anchors.bottom: parent.bottom      
anchors.margins: 20      
height: 40      
color: "darkGreen"      
Text{      
anchors.centerIn: parent      
text: "Add item!"      
}      
MouseArea{   //点击时给模型添加一个元素      
anchors.fill: parent      
onClicked: {      
theModel.append({"number": ++parent.count});      
}      
}      
property int count: 9      
}      
GridView{      
anchors.fill: parent      
anchors.margins: 20      
anchors.bottomMargin: 80      
clip: true      
model: theModel      
cellWidth: 45      
cellHeight: 45      
delegate: numberDelegate      
}      
Componment{     //点击代理时,移除一个元素      
id: numberDelegate      
Rectangle{      
id: wrapper      
width: 40      
height: 40      
color: "lightGreen"      
Text{      
anchors.centerIn: parent      
font.pixelSize: 10      
text: number      
}      
}      
MouseArea{      
anchors.fill: parent      
onClicked: {      
if(!wrapper.GridView.delayRemove){      
theModel.remove(index);      
}      
}      
}      
GridView.onRemove: SequentialAnimation{      
PropertyAction{      
target: wrapper;      
property: "GridView.delayRemove"      
value: true      
}      
}      
GridView.onAdd: SequentialAnimation{      
NumberAnimation{      
NumberAnimation{      
target: wrapper      
property: "scale"      
from: 0; to: 1; duration:250      
easing.type = ...      
}      
}      
}      
}      
}      
//形变的代理,路径视图,性能协调等知识就先不写了,写够了,路径视图等爱动弹时再单独补充吧      
//本文主要翻译自英文文档。。。          

继续阅读