扩展QML - 使用列表属性类型

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

目前,一个PieChart只能有一个PieSlice。理想情况下,图表应该 有多个切片,具有不同的颜色和大小。为了实现这一点,我们可以 有一个slices属性,该属性接受一个PieSlice项目的列表:

 4import Charts
 5import QtQuick
 6
 7Item {
 8    width: 300; height: 200
 9
10    PieChart {
11        anchors.centerIn: parent
12        width: 100; height: 100
13
14        slices: [
15            PieSlice {
16                anchors.fill: parent
17                color: "red"
18                fromAngle: 0; angleSpan: 110
19            },
20            PieSlice {
21                anchors.fill: parent
22                color: "black"
23                fromAngle: 110; angleSpan: 50
24            },
25            PieSlice {
26                anchors.fill: parent
27                color: "blue"
28                fromAngle: 160; angleSpan: 100
29            }
30        ]
31    }
32}

为此,我们将PieChart中的pieSlice属性替换为 slices属性,声明为 ListProperty类型的类变量。 ListProperty类允许在 QML扩展中创建列表属性。我们将pieSlice()函数替换为返回切片列表的slices() 函数,并添加一个内部的appendSlice() 函数(如下所述)。我们还使用一个列表来存储内部的切片列表,如_slices所示:

62@QmlElement
63class PieChart (QQuickItem):
64    def __init__(self, parent=None):
65        QQuickItem.__init__(self, parent)
75        self._name = value
76
77    def appendSlice(self, _slice):
78        _slice.setParentItem(self)
79        self._slices.append(_slice)

尽管slices属性没有关联的设置器,但由于ListProperty的工作方式,它仍然可以修改。我们指示每当从QML发出请求向列表中添加项目时,应调用内部的PieChart.appendSlice()函数。

appendSlice() 函数简单地像之前一样设置父项,并将新项添加到 _slices 列表中。如你所见,ListProperty 的 append 函数被调用时带有两个参数:列表属性和要追加的项。

PieSlice 类也被修改为包含 fromAngleangleSpan 属性,并根据这些值绘制切片。如果您已经阅读了本教程的前几页,这是一个简单的修改,因此这里不显示代码。

下载 这个 示例

// 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 {
        anchors.centerIn: parent
        width: 100; height: 100

        slices: [
            PieSlice {
                anchors.fill: parent
                color: "red"
                fromAngle: 0; angleSpan: 110
            },
            PieSlice {
                anchors.fill: parent
                color: "black"
                fromAngle: 110; angleSpan: 50
            },
            PieSlice {
                anchors.fill: parent
                color: "blue"
                fromAngle: 160; angleSpan: 100
            }
        ]
    }
}
# 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/chapter5-listproperties example from Qt v5.x"""

import os
from pathlib import Path
import sys

from PySide6.QtCore import Property, QUrl
from PySide6.QtGui import QGuiApplication, QPen, QPainter, QColor
from PySide6.QtQml import QmlElement, ListProperty
from PySide6.QtQuick import QQuickPaintedItem, QQuickView, QQuickItem

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


@QmlElement
class PieSlice (QQuickPaintedItem):
    def __init__(self, parent=None):
        QQuickPaintedItem.__init__(self, parent)
        self._color = QColor()
        self._fromAngle = 0
        self._angleSpan = 0

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

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

    @Property(int, final=True)
    def fromAngle(self):
        return self._angle

    @fromAngle.setter
    def fromAngle(self, value):
        self._fromAngle = value

    @Property(int, final=True)
    def angleSpan(self):
        return self._angleSpan

    @angleSpan.setter
    def angleSpan(self, value):
        self._angleSpan = value

    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), self._fromAngle * 16, self._angleSpan * 16)


@QmlElement
class PieChart (QQuickItem):
    def __init__(self, parent=None):
        QQuickItem.__init__(self, parent)
        self._name = u''
        self._slices = []

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

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

    def appendSlice(self, _slice):
        _slice.setParentItem(self)
        self._slices.append(_slice)

    slices = ListProperty(PieSlice, appendSlice, final=True)


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)