文章

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定义了每个数据项的外观和行为。

模型数据一般定义成如下几种类型:QStringListQVariantListQObjectListQAbstractItemModel

使用方式是:在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
    }

    // ...省略其他代码...
}
  • 注意:有两种方式将modelview连接起来:deletegateRepeater。比如Qt内置的ListViewGridView等,使用Repeater,会将所有数据都加载进来,使用delegate将根据视图需要进行加载。
  • 注意delegate会针对每一项数据生成一个delegate实例。

个人理解:增加delegate这一个桥接层,可以在modelview之间进行自定义的处理,比如数据过滤,数据转换等,以及使用DelegateChooser动态切换不同的delegate

本文由作者按照 CC BY 4.0 进行授权