一、Model-View
1.1、Qt中的model-view是什么
有点类似MVC模式,Qt中,数据通过model-view模式,将数据和显示分离开来
model: 数据模型,负责存储和管理数据view: 视图容器,负责布局和显示管理delegate: 可视化代理,负责单个数据项的可视化呈现
1.2、有哪些view
常见视图组件:
ListView- 列表视图GridView- 网格视图TableView- 表格视图PathView- 路径视图Repeater- 重复器(非视图组件,但常用于重复创建项目)
1.3、Repeater
Repeater是Qt中一个非常有用的组件,它可以重复渲染一组数据。它类似于其他框架中的列表或表格控件,但它的灵活性更高,因为它可以处理任意类型的模型(如字符串、图像等)。
- 属性:
- count: 创建多少项
- delegate: 每个项的渲染模板
- model: 数据源
- 信号:
- itemAdded(int index, Item item): 当一个新的项被添加到Repeater时发出。
- onItemAdded(int index, Item item): 处理信号
- itemRemoved(int index, Item item): 当一个项被从Repeater中移除时发出。
- onItemRemoved: 处理信号
- itemAdded(int index, Item item): 当一个新的项被添加到Repeater时发出。
注意:
Repeater通常会创建其所有delegate项;如果存在大量delegate项,并且并非所有项都必须同时可见,会降低效率,需要考虑其他view
示例代码:
javascript
import QtQuick
Column{
spacing:10
Repeater{
model: 5
delegate: Rectangle{
width: 100; height: 50
color:"red"
}
onItemAdded: {
console.log("item " + index + "added")
}
onItemRemoved: {
console.log("item" + index + "removed")
}
}
}
1.4、ListView
类似于Repaeter,只不过delegate之间有间隔,并且可以滑动,所谓的瀑布流布局
关键属性:
spacing: 项间距orientation: 布局方向(默认垂直)clip: 是否裁剪超出区域的内容cacheBuffer: 预渲染缓冲区大小currentIndex: 当前选中项索引highlight: 高亮组件
示例代码:
javascript
ListView{
anchors.fill: parent
anchors.margins: 20
spacing: 15
clip: true // 默认是false,设置为true,在视觉上,会看不见元素创建与销毁的过程
model: 100
cacheBuffer: 20 // 如果需要展示的元素过多,可以设置缓存区大小,节省频繁创建销毁的内存开销
delegate: Rectangle{
required property int index
width: 20
height: 25
color: "red"
Component.onCompleted: {
console.log(index + " added")
}
Component.onDestruction: {
console.log(index + " deleted")
}
}
}
1.5、GridView
使用GridView可以创建网格布局,类似于ListView,只不过是将delegate布局成网格
关键属性:
cellWidth、cellHeight: 网格大小flow: 布局流向(FlowTopToBottom/FlowLeftToRight)layoutDirection: 布局方向(LeftToRight/RightToLeft)
示例代码:
javascript
GridView{
anchors.fill: parent
clip: true
model:100
cellWidth:40 // 设置每个小网格的长宽
cellHeight:40
flow:GridView.FlowTopToBottom // 布局方式是从上到下
//flow:GridView.FlowLeftToRight // 布局方式是从左到右
delegate: Rectangle{
width: 20
height: 20
color: "red"
}
}
1.6、Delegete
delegate翻译过来是代理,委托的意识;在model-view中,delegate是介于数据和视图之间的桥梁
- 从model获取数据
- 定义数据可视化方式
- 响应视图状态变化
示例代码:
javascript
ListView{
anchors.fill: parent
anchors.margins: 20
spacing: 15
clip: true // 默认是false,设置为true,在视觉上,会看不见元素创建与销毁的过程
model: 100
cacheBuffer: 20 // 如果需要展示的元素过多,可以设置缓存区大小,节省频繁创建销毁的内存开销
delegate: numberDelegate
}
Component{
id: numberDelegate
Rectangle{
required property int index
width: 40
height: 25
color: ListView.isCurrentItem ? "black" : "red"
id: wrapper
Text{
id:label1
text: wrapper.index
anchors.centerIn: parent
}
}
}
delegate动画- onAdd
- onRemove
示例代码:
javascript
delegate: Rectangle {
required property int index
// 添加动画
GridView.onAdd: SequentialAnimation {
NumberAnimation {
property: "scale"; from: 0; to: 1; duration: 300
}
}
// 移除动画
GridView.onRemove: SequentialAnimation {
NumberAnimation {
property: "scale"; to: 0; duration: 300
}
}
}
二、测试
场景:两个按钮,一个按钮点击,在网格中添加一个元素;另一个按钮点击,删除最后一个元素
javascript
import QtQuick
Rectangle{
anchors.fill: parent
gradient: Gradient{
GradientStop{position:0.0; color:"#dbdbdb"}
GradientStop{position:1.0; color:"#5fc9f8"}
}
// model
ListModel{
id:theModel
ListElement{ num:0}
ListElement{ num:1}
ListElement{ num:2}
ListElement{ num:3}
}
//button
Rectangle{
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 20
height: 40
color: "#53f769"
border.color: Qt.lighter(color, 1.1)
Text{
anchors.centerIn: parent
text: qsTr("add")
}
MouseArea{
anchors.fill: parent
onClicked: {
theModel.append({"num": theModel.count})
console.log(theModel.count)
}
}
}
// 删除按钮
Rectangle{
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 20
anchors.bottomMargin: 60 // 在添加按钮上方
height: 40
color: "#f75353"
border.color: Qt.lighter(color, 1.1)
Text{
anchors.centerIn: parent
text: qsTr("remove last")
}
MouseArea{
anchors.fill: parent
onClicked: {
if (theModel.count > 0) {
theModel.remove(theModel.count - 1)
console.log(theModel.count)
}
}
}
}
// view
GridView{
anchors.fill: parent
anchors.margins: 20
anchors.bottomMargin: 80
clip: true
cellHeight: 40
cellWidth: 60
model:theModel
delegate: numberDelegate
}
// Delegate
Component{
id: numberDelegate
Rectangle{
id: wrapper
required property int index
required property int num
gradient: Gradient{
GradientStop{position:0.0; color:"#dbdbdb"}
GradientStop{position:1.0; color:"#5fc9f8"}
}
width: 40
height: 25
color: ListView.isCurrentItem ? "black" : "red"
Text{
id:label1
text: qsTr(wrapper.index)
anchors.centerIn: parent
}
// 添加动画
GridView.onAdd:addAnimation.start()
GridView.onRemove:removeAnimation.start()
NumberAnimation{
id:addAnimation
target:wrapper
property: "scale"
from: 0
to:1
duration: 250
easing.type: Easing.InOutQuad
}
NumberAnimation{
id:removeAnimation
target:wrapper
property: "scale"
to:0
duration: 250
easing.type: Easing.InOutQuad
}
}
}
}
