Extending QML - Using Custom Property Types¶
This is the fourth of a series of 6 examples forming a tutorial about extending QML with Python.
The PieChart type currently has a string-type property and a color-type property.
It could have many other types of properties. For example, it could have an
int-type property to store an identifier for each chart:
class PieChart(QQuickPaintedItem):
chartIdChanged = Signal()
@Property(int, notify=chartIdChanged)
def chartId(self):
pass
@chartId.setter
def setChartId(self, chartId):
pass
// QML
PieChart {
...
chartId: 100
}
Aside from int, we could use various other property types. Many of the Qt
data types such as QColor, QSize
and QRect are automatically
supported from QML.
If we want to create a property whose type is not supported by QML by default, we need to register the type with the QML engine.
For example, let’s replace the use of the property with a type called
PieSlice that has a color property. Instead of assigning a color,
we assign an PieSlice value which itself contains a color:
4import Charts
5import QtQuick
6
7Item {
8 width: 300; height: 200
9
10 PieChart {
11 id: chart
12 anchors.centerIn: parent
13 width: 100; height: 100
14
15 pieSlice: PieSlice {
16 anchors.fill: parent
17 color: "red"
18 }
19 }
20
21 Component.onCompleted: console.log("The pie is colored " + chart.pieSlice.color)
22}
Like PieChart, this new PieSlice type inherits from
QQuickPaintedItem, is exposed via @QmlElement and declares
its properties with the Property decorator:
21
22@QmlElement
23class PieSlice (QQuickPaintedItem):
24
25 def __init__(self, parent=None):
26 QQuickPaintedItem.__init__(self, parent)
27 self._color = QColor()
28
29 @Property(QColor, final=True)
30 def color(self):
31 return self._color
32
33 @color.setter
34 def color(self, value):
35 self._color = value
36
37 def paint(self, painter):
38 pen = QPen(self._color, 2)
39 painter.setPen(pen)
40 painter.setRenderHints(QPainter.RenderHint.Antialiasing, True)
To use it in PieChart, we modify the color property declaration
and associated method signatures:
58
59 @Property(PieSlice, final=True)
60 def pieSlice(self):
61 return self._pieSlice
62
63 @pieSlice.setter
64 def pieSlice(self, value):
65 self._pieSlice = value
There is one thing to be aware of when implementing setPieSlice(). The
PieSlice is a visual item, so it must be set as a child of the PieChart
using setParentItem() so that the PieChart knows to paint
this child item when its contents are drawn.
As with PieChart, we add the Charts type namespace, version 1.0:
15
16# To be used on the @QmlElement decorator
17# (QML_IMPORT_MINOR_VERSION is optional)
18QML_IMPORT_NAME = "Charts"
# 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/chapter4-customPropertyTypes example
from Qt v5.x"""
from pathlib import Path
import sys
from PySide6.QtCore import Property
from PySide6.QtGui import QGuiApplication, QPen, QPainter, QColor
from PySide6.QtQml import QmlElement
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()
@Property(QColor, final=True)
def color(self):
return self._color
@color.setter
def color(self, value):
self._color = 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), 90 * 16, 290 * 16)
@QmlElement
class PieChart (QQuickItem):
def __init__(self, parent=None):
QQuickItem.__init__(self, parent)
self._name = None
self._pieSlice = None
@Property(str, final=True)
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
@Property(PieSlice, final=True)
def pieSlice(self):
return self._pieSlice
@pieSlice.setter
def pieSlice(self, value):
self._pieSlice = value
self._pieSlice.setParentItem(self)
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
view = QQuickView()
view.setResizeMode(QQuickView.ResizeMode.SizeRootObjectToView)
view.engine().addImportPath(Path(__file__).parent)
view.loadFromModule("Charts", "App")
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) 2017 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: chart
anchors.centerIn: parent
width: 100; height: 100
pieSlice: PieSlice {
anchors.fill: parent
color: "red"
}
}
Component.onCompleted: console.log("The pie is colored " + chart.pieSlice.color)
}
module Charts
typeinfo chapter4-customPropertyTypes.qmltypes
depends QtQuick
App 254.0 App.qml