Extending QML (advanced) - BirthdayParty Base Project#
This is the first of a series of 6 examples forming a tutorial using the example of a birthday party to demonstrate some of the advanced features of QML. The code for the various features explained below is based on this birthday party project and relies on some of the material in the basic tutorial. This simple example is then expanded upon to illustrate the various QML extensions explained below. The complete code for each new extension to the code can be found at the end of the respective page.
The base project defines the Person
class and the BirthdayParty
class,
which model the attendees and the party itself respectively.
13@QmlElement
14class Person(QObject):
15 name_changed = Signal()
16 shoe_size_changed = Signal()
17
18 def __init__(self, parent=None):
19 super().__init__(parent)
20 self._name = ''
21 self._shoe_size = 0
22
23 @Property(str, notify=name_changed, final=True)
24 def name(self):
25 return self._name
26
27 @name.setter
28 def name(self, n):
29 if self._name != n:
30 self._name = n
31 self.name_changed.emit()
32
33 @Property(int, notify=shoe_size_changed, final=True)
34 def shoe_size(self):
35 return self._shoe_size
36
37 @shoe_size.setter
38 def shoe_size(self, s):
39 if self._shoe_size != s:
40 self._shoe_size = s
41 self.shoe_size_changed.emit()
16@QmlElement
17class BirthdayParty(QObject):
18 host_changed = Signal()
19 guests_changed = Signal()
20
21 def __init__(self, parent=None):
22 super().__init__(parent)
23 self._host = None
24 self._guests = []
25
26 @Property(Person, notify=host_changed, final=True)
27 def host(self):
28 return self._host
29
30 @host.setter
31 def host(self, h):
32 if self._host != h:
33 self._host = h
34 self.host_changed.emit()
35
36 def guest(self, n):
37 return self._guests[n]
38
39 def guestCount(self):
40 return len(self._guests)
41
42 def appendGuest(self, guest):
43 self._guests.append(guest)
44 self.guests_changed.emit()
45
46 guests = ListProperty(Person, appendGuest, notify=guests_changed, final=True)
All the information about the party can then be stored in the corresponding QML file.
4import People
5
6BirthdayParty {
7 host: Person {
8 name: "Bob Jones"
9 shoe_size: 12
10 }
11 guests: [
12 Person { name: "Leo Hodges" },
13 Person { name: "Jack Smith" },
14 Person { name: "Anne Brown" }
15 ]
16}
The main.py
file creates a simple shell application that displays whose
birthday it is and who is invited to their party.
17engine = QQmlEngine()
18engine.addImportPath(Path(__file__).parent)
19component = QQmlComponent(engine)
20component.loadFromModule("People", "Main")
21party = component.create()
The app outputs the following summary of the party:
"Bob Jones" is having a birthday!
They are inviting:
"Leo Hodges"
"Jack Smith"
"Anne Brown"
Outlook#
The following sections go into how to add support for Boy
and Girl
attendees instead of just Person
by using inheritance and coercion, how to
make use of default properties to implicitly assign attendees of the party as
guests, how to assign properties as groups instead of one by one, how to use
attached objects to keep track of invited guests’ reponses, how to use a
property value source to display the lyrics of the happy birthday song over
time, and how to expose third party objects to QML.
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
"""PySide6 port of the qml/examples/qml/tutorials/extending-qml-advanced/advanced1-Base-project example from Qt v6.x"""
from pathlib import Path
import sys
from PySide6.QtCore import QCoreApplication
from PySide6.QtQml import QQmlComponent, QQmlEngine
from person import Person
from birthdayparty import BirthdayParty
app = QCoreApplication(sys.argv)
engine = QQmlEngine()
engine.addImportPath(Path(__file__).parent)
component = QQmlComponent(engine)
component.loadFromModule("People", "Main")
party = component.create()
if not party:
print(component.errors())
del engine
sys.exit(-1)
host = party.host
print(f"{host.name} is having a birthday!\nThey are inviting:")
for g in range(party.guestCount()):
name = party.guest(g).name
print(f" {name}")
del engine
sys.exit(0)
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtCore import QObject, Property, Signal
from PySide6.QtQml import QmlElement, ListProperty
from person import Person
# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "People"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class BirthdayParty(QObject):
host_changed = Signal()
guests_changed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._host = None
self._guests = []
@Property(Person, notify=host_changed, final=True)
def host(self):
return self._host
@host.setter
def host(self, h):
if self._host != h:
self._host = h
self.host_changed.emit()
def guest(self, n):
return self._guests[n]
def guestCount(self):
return len(self._guests)
def appendGuest(self, guest):
self._guests.append(guest)
self.guests_changed.emit()
guests = ListProperty(Person, appendGuest, notify=guests_changed, final=True)
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtCore import QObject, Property, Signal
from PySide6.QtQml import QmlElement
# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "People"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class Person(QObject):
name_changed = Signal()
shoe_size_changed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._name = ''
self._shoe_size = 0
@Property(str, notify=name_changed, final=True)
def name(self):
return self._name
@name.setter
def name(self, n):
if self._name != n:
self._name = n
self.name_changed.emit()
@Property(int, notify=shoe_size_changed, final=True)
def shoe_size(self):
return self._shoe_size
@shoe_size.setter
def shoe_size(self, s):
if self._shoe_size != s:
self._shoe_size = s
self.shoe_size_changed.emit()
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import People
BirthdayParty {
host: Person {
name: "Bob Jones"
shoe_size: 12
}
guests: [
Person { name: "Leo Hodges" },
Person { name: "Jack Smith" },
Person { name: "Anne Brown" }
]
}
module People
typeinfo coercion.qmltypes
Main 1.0 Main.qml