扩展 QML - 使用列表属性类型#
这是关于用 Python 扩展 QML 的 6 个示例教程中的第 5 个。
目前,饼图只能有一个 PieSlice.
理想情况下,图表应该有多个片段,颜色和大小不同。为此,我们可以有一个接受 PieSlice
项目列表的 slices
属性。
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
属性,该属性被声明为 QQmlListProperty
类型的类变量。QQmlListProperty
类允许在 QML 扩展中创建列表属性。我们将 pieSlice()
函数替换为 slices()
函数,该函数返回一个切片列表,并添加了一个内部的 appendSlice()
函数(下文将讨论)。我们还使用一个列表来存储内部切片列表,作为 _slices
62class PieChart (QQuickItem):
63 def __init__(self, parent=None):
64 QQuickItem.__init__(self, parent)
65 self._name = u''
75
76 def appendSlice(self, _slice):
77 _slice.setParentItem(self)
78 self._slices.append(_slice)
79
尽管 slices
属性没有相关的设置器,但是由于 QQmlListProperty
的工作方式,它仍然是可修改的。我们指出,当从 QML 发出请求以向列表添加项目时,应该调用内部 PieChart.appendSlice()
函数。
appendSlice()
函数简单地将父项目设置如前,并将新项目添加到 _slices
列表中。正如你所看到的,QQmlListProperty
的 append 函数调用时需要两个参数:列表属性和要附加的项目。
PieSlice
类也被修改以包括 fromAngle
和 angleSpan
属性,并按这些值绘制切片。如果你已经阅读了本教程的前几页,这是一个简单的修改,所以这里没有显示代码。
// 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
"""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.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.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)