扩展QML - 连接到C++方法和信号

这是关于使用Python扩展QML的教程系列中的第二个示例,该系列共有6个示例。

假设我们希望PieChart有一个clearChart()方法,该方法可以清除图表并发出chartCleared信号。我们的app.qml将能够调用clearChart()并接收chartCleared()信号,如下所示:

 4import Charts
 5import QtQuick
 6
 7Item {
 8    width: 300; height: 200
 9
10    PieChart {
11        id: aPieChart
12        anchors.centerIn: parent
13        width: 100; height: 100
14        color: "red"
15
16        onChartCleared: console.log("The chart has been cleared")
17    }
18
19    MouseArea {
20        anchors.fill: parent
21        onClicked: aPieChart.clearChart()
22    }
23
24    Text {
25        anchors {
26            bottom: parent.bottom;
27            horizontalCenter: parent.horizontalCenter;
28            bottomMargin: 20
29        }
30        text: "Click anywhere to clear the chart"
31    }
32}

为此,我们在C++类中添加了一个clearChart()方法和一个chartCleared()信号:

54
55    @Slot()  # This should be something like @Invokable
56    def clearChart(self):
57        self.color = Qt.transparent
58        self.update()

使用@Slot使得clearChart()方法对Qt元对象系统可用,进而对QML可用。该方法简单地将颜色更改为Qt::transparent,重新绘制图表,然后发出chartCleared()信号:

21
22@QmlElement
23class PieChart(QQuickPaintedItem):
24

现在当我们运行应用程序并点击窗口时,饼图消失, 应用程序输出:

qml: The chart has been cleared

下载 这个 示例

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations

"""PySide6 port of the qml/tutorials/extending-qml/chapter2-methods example from Qt v5.x"""

import os
from pathlib import Path
import sys

from PySide6.QtCore import Property, Signal, Slot, Qt, QUrl
from PySide6.QtGui import QGuiApplication, QPen, QPainter, QColor
from PySide6.QtQml import QmlElement
from PySide6.QtQuick import QQuickPaintedItem, QQuickView

# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "Charts"
QML_IMPORT_MAJOR_VERSION = 1


@QmlElement
class PieChart(QQuickPaintedItem):

    chartCleared = Signal()
    nameChanged = Signal()

    def __init__(self, parent=None):
        QQuickPaintedItem.__init__(self, parent)
        self._name = u''
        self._color = QColor()

    def paint(self, painter):
        pen = QPen(self.color, 2)
        painter.setPen(pen)
        painter.setRenderHints(QPainter.RenderHint.Antialiasing, True)
        painter.drawPie(self.boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16)

    @Property(QColor, final=True)
    def color(self):
        return self._color

    @color.setter
    def color(self, value):
        self._color = value

    @Property(str, notify=nameChanged, final=True)
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @Slot()  # This should be something like @Invokable
    def clearChart(self):
        self.color = Qt.transparent
        self.update()
        self.chartCleared.emit()


if __name__ == '__main__':
    app = QGuiApplication(sys.argv)

    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)
    qml_file = os.fspath(Path(__file__).resolve().parent / 'app.qml')
    view.setSource(QUrl.fromLocalFile(qml_file))
    if view.status() == QQuickView.Status.Error:
        sys.exit(-1)
    view.show()
    res = app.exec()
    # Deleting the view before it goes out of scope is required to make sure all child QML instances
    # are destroyed in the correct order.
    del view
    sys.exit(res)
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import Charts
import QtQuick

Item {
    width: 300; height: 200

    PieChart {
        id: aPieChart
        anchors.centerIn: parent
        width: 100; height: 100
        color: "red"

        onChartCleared: console.log("The chart has been cleared")
    }

    MouseArea {
        anchors.fill: parent
        onClicked: aPieChart.clearChart()
    }

    Text {
        anchors {
            bottom: parent.bottom;
            horizontalCenter: parent.horizontalCenter;
            bottomMargin: 20
        }
        text: "Click anywhere to clear the chart"
    }
}