Model-View-Delegate是Qt中复合控件的一种设计模式
如ListView,TableView,ComboBox等控件,都会用到这种设计模式
设计原理
【Model-View-Delegate】翻译成中文就是【模型-视图-代理】,它的思想是这样的:
- 用一个model对线来存储数据源,一般是一个数组或List
- View只绘制控件的基础部分,比如ComboBox,它只负责文本标签和下拉箭头的绘制
- 复合控件的子元素交给delegate去绘制,delegate定义了如何将model中的单个元素绘制成一个子项视图
示例代码
Model-View-Delegate界面设计模式既适用于Qt Widget,也适用于Qt Quick,这里我们以Qt Quick为例
//main.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
ComboBox {
id: combo
width: 300
height: 50
//数据源
model: [{
"name": "Programmer A",
"age": 25
}, {
"name": "Programmer B",
"age": 26
}, {
"name": "Programmer C",
"age": 27
}]
//选中项
currentIndex: -1
//定义某一下拉项的视图
delegate: ItemDelegate {
width: combo.width
contentItem: Text {
text: modelData.name + " " + modelData.age //modelData属性对应某一下拉项的数据
color: "darkgreen"
font: combo.font
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
highlighted: combo.highlightedIndex == index //highlighted表示鼠标正悬浮在当前项上
}
//定义主文本标签的视图
contentItem: Text {
leftPadding: 10
rightPadding: indicator.width + 10
text: combo.currentIndex < 0 ? "please select your option" : model[combo.currentIndex].name
font: combo.font
color: combo.pressed ? "green" : "darkgreen"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
//定义主文本标签后的下拉箭头
indicator: Canvas {
x: combo.width - combo.rightPadding - width
y: combo.height / 2 - height / 2
width: 12
height: 8
contextType: "2d"
onPaint: {
context.reset()
context.moveTo(0, 0)
context.lineTo(width, 0)
context.lineTo(width / 2, height)
context.closePath()
context.fillStyle = combo.pressed ? "green" : "darkgreen"
context.fill()
}
Connections {
target: combo
onPressedChanged: indicator.requestPaint()
}
}
//定义主文本标签背景边框
background: Rectangle {
border.color: combo.pressed ? "green" : "darkgreen"
border.width: 1
radius: 2
}
//定义下拉弹窗样式
popup: Popup {
y: combo.height - 1
width: combo.width
height: listview.contentHeight
padding: 1
contentItem: ListView {
id: listview
model: combo.delegateModel
currentIndex: combo.highlightedIndex
clip: true
ScrollIndicator.vertical: ScrollIndicator {
}
}
background: Rectangle {
border.color: "darkgreen"
radius: 2
}
}
}
//main.cpp
#include <QGuiApplication>
#include <QQuickView>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl("qrc:///main.qml"));
view.show();
return app.exec();
}