QML基础语法积累
1. 信号与 Connections
信号一般用于组件封装,在外部声明的组件内声明信号处理器。Connections则提供另外一种方式:即在被调用组件外部使用信号并使用信号处理器。
1.1. 信号的语法及使用
信号语法:
1
signal <signalName>([<parameterName>:<parameterType>[,...]])
信号处理器语法:
1
2
3
// on: 固定关键字
// Signal: 信号名,首字母必须大写
on<Signal>
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Item {
signal mySignal(param1: int, param2: string)
MouseArea {
anchors.fill: parent
onClicked: {
mySignal(42, "Hello")
}
}
// Qt6 要求信号处理器显式声明参数
onMySignal: (param1, param2) => {
console.log("Signal received with param1:", param1, "and param2:", param2)
}
}
1.2. 属性值改变信号
QML类型提供内建属性值改变信号,这个属性属性值改变就会自动发出信号。属性值改变信号的命名规则是 on<PropertyName>Changed。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Rectangle {
width: 100
height: 100
color: "red"
onWidthChanged: width => {
console.log("Width changed to:", width);
}
MouseArea {
anchors.fill: parent
onClicked: {
width += 10
}
}
}
1.3. Connections
Connections 允许在组件外部处理信号。语法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
// 连接button1,信号被分发到这
Connections {
target: button1
function onClicked() {
console.log("cnnection func")
}
}
// 被连接对象
Button {
id: button1
width: 200
height: 100
text: "button1"
font.pixelSize: 30
onClicked: { // 直接定义信号处理器的使用方式
console.log("button1 func")
}
}
}
1.4. 自定义C++/QML交互:C++模块属性及在QML中使用
- 在C++模块中,使用
Q_PROPERTY宏定义属性,并指定NOTIFY信号。此时,QML信号处理器的语法与属性值改变信号相同:on<PropertyName>Changed。 - 在
QML中,可以使用Connections连接C++对象的信号,也可以使用直接绑定到C++属性的方式。
示例:
1
2
3
4
5
6
7
class NuoQianMapController : public QObject {
Q_OBJECT
Q_PROPERTY(QGeoCoordinate center READ center WRITE setCenter NOTIFY centerChanged)
Q_PROPERTY(double zoomLevel READ zoomLevel WRITE setZoomLevel NOTIFY zoomLevelChanged)
// ...省略其他代码...
};
Connections使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
map {
Connections {
target: NuoQianMapController
function onCenterChanged() {
// 处理中心点变化
}
function onZoomLevelChanged() {
// 处理缩放级别变化
}
}
}
直接绑定属性示例:
1
2
3
4
5
6
7
map {
center: NuoQianMapController.center
zoomLevel: NuoQianMapController.zoomLevel
// 也可以使用property绑定,如果是复杂类型,则在QML中property定义为var类型
property var mapCenter: NuoQianMapController.center
}
- 注意:如果
C++信号中包含不被QML支持的参数类型,则无法在QML中使用该信号处理器。另外,信号不能同名,即不能重载,QML无法区分。
2. Model-View-Delegate
QML中的Model-View-Delegate模式用于处理数据的显示和交互。Model表示数据源,View负责显示数据,而Delegate定义了每个数据项的外观和行为。
模型数据一般定义成如下几种类型:QStringList,QVariantList,QObjectList,QAbstractItemModel。
使用方式是:在view中指定model属性为数据模型,然后使用delegate属性定义每个数据项的外观和行为。
示例:
class NuoQianCoverageAreaManager : public QObject {
Q_OBJECT
Q_PROPERTY(QQmlListProperty<NuoQianCoverageArea> coverageAreas READ coverageAreas NOTIFY coverageAreasChanged)
Q_PROPERTY(int count READ count NOTIFY coverageAreasChanged)
// ...省略其他代码...
};
1
2
3
4
5
6
7
8
9
// view.qml
MapItemView {
id: view
model: NuoQianCoverageAreaManager.coverageAreas
delegate: CoverageAreaView {
areaData: modelData
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// delegate实现
// CoverageAreaView.qml
MapItemGroup {
id: coverageGroup
property var areaData: null
// 覆盖区域填充
MapPolygon {
path: areaData ? areaData.borderPath : []
color: areaData ? areaData.color : "#4444FF88"
border.color: areaData ? Qt.darker(areaData.color, 1.5) : "#3333DD"
border.width: 2
visible: areaData && areaData.visible && path.length > 0
z: 40
}
// ...省略其他代码...
}
- 注意:有两种方式将
model与view连接起来:deletegate与Repeater。比如Qt内置的ListView,GridView等,使用Repeater,会将所有数据都加载进来,使用delegate将根据视图需要进行加载。 - 注意:
delegate会针对每一项数据生成一个delegate实例。
个人理解:增加delegate这一个桥接层,可以在model与view之间进行自定义的处理,比如数据过滤,数据转换等,以及使用DelegateChooser动态切换不同的delegate。
本文由作者按照 CC BY 4.0 进行授权