扩展QML(高级)- 属性值源¶
这是使用生日派对示例演示QML一些高级功能的6个示例系列中的最后一个。
在聚会期间,客人需要为主人唱歌。如果程序能够显示为场合定制的歌词来帮助客人,那将非常方便。为此,使用了一个属性值源来随时间生成歌曲的歌词。
13
14@QmlElement
15class HappyBirthdaySong(QPyQmlPropertyValueSource):
16 name_changed = Signal()
17
18 def __init__(self, parent=None):
19 super().__init__(parent)
20
21 self.m_target = None
22 self.m_name = ""
23 self.m_line = -1
24 self.m_lyrics = []
25
26 self.m_timer = QTimer(self)
27 self.m_timer.timeout.connect(self.advance)
28 self.m_timer.start(1000)
29
30 def setTarget(self, property):
31 self.m_target = property
32
33 @Property(str, notify=name_changed, final=True)
34 def name(self):
35 return self.m_name
36
37 @name.setter
38 def name(self, n):
39 if self.m_name != n:
40 self.m_name = n
41 self.m_lyrics = ["Happy birthday to you,",
42 "Happy birthday to you,",
43 f"Happy birthday dear {self.m_name},",
44 "Happy birthday to you!",
45 ""]
46
47 @Slot()
48 def advance(self):
49 self.m_line = (self.m_line + 1) % len(self.m_lyrics)
类 HappyBirthdaySong
被添加为值源。它必须继承自 QQmlPropertyValueSource
并实现其接口。setTarget()
函数用于定义此源作用于哪个属性。在这种情况下,值源写入 BirthdayParty
的 announcement
属性,以随时间显示歌词。它有一个内部计时器,导致聚会的 announcement
属性被重复设置为歌词的下一行。
在QML中,HappyBirthdaySong
在BirthdayParty
中被实例化。
其签名中的on
关键字用于指定值源所针对的属性,在本例中为announcement
。HappyBirthdaySong
对象的name
属性也绑定到聚会主持人的名字。
6BirthdayParty {
7 HappyBirthdaySong on announcement { name: "Bob Jones" }
程序显示聚会开始使用partyStarted
信号的时间,然后重复打印以下生日快乐诗句:
Happy birthday to you,
Happy birthday to you,
Happy birthday dear Bob Jones,
Happy birthday to you!
# 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/examples/qml/tutorials/extending-qml-advanced/advanced6-Property-value-source example
from Qt v6.x"""
from pathlib import Path
import sys
from PySide6.QtCore import QCoreApplication
from PySide6.QtQml import QQmlComponent, QQmlEngine, qmlAttachedPropertiesObject
from person import Boy, Girl # noqa: F401
from birthdayparty import BirthdayParty
from happybirthdaysong import HappyBirthdaySong # noqa: F401
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!")
if isinstance(host, Boy):
print("He is inviting:")
else:
print("She is inviting:")
for g in range(party.guestCount()):
guest = party.guest(g)
name = guest.name
rsvp_date = None
attached = qmlAttachedPropertiesObject(BirthdayParty, guest, False)
if attached:
rsvp_date = attached.rsvp.toString()
if rsvp_date:
print(f" {name} RSVP date: {rsvp_date}")
else:
print(f" {name} RSVP date: Hasn't RSVP'd")
party.startParty()
r = app.exec()
del engine
sys.exit(r)
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
from PySide6.QtCore import QDate, QObject, ClassInfo, Property, QTime, Signal
from PySide6.QtQml import QmlAnonymous, QmlAttached, 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
@QmlAnonymous
class BirthdayPartyAttached(QObject):
rsvp_changed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._rsvp = QDate()
@Property(QDate, notify=rsvp_changed, final=True)
def rsvp(self):
return self._rsvp
@rsvp.setter
def rsvp(self, d):
if self._rsvp != d:
self._rsvp = d
self.rsvp_changed.emit()
@QmlElement
@ClassInfo(DefaultProperty="guests")
@QmlAttached(BirthdayPartyAttached)
class BirthdayParty(QObject):
announcement_changed = Signal()
host_changed = Signal()
guests_changed = Signal()
partyStarted = Signal(QTime)
def __init__(self, parent=None):
super().__init__(parent)
self._announcement = ""
self._host = None
self._guests = []
def startParty(self):
self.partyStarted.emit(QTime.currentTime())
@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()
@Property(str, notify=announcement_changed, final=True)
def announcement(self):
return self._announcement
@announcement.setter
def announcement(self, a):
if self._announcement != a:
self._announcement = a
self.announcement_changed.emit()
print(a)
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()
@staticmethod
def qmlAttachedProperties(self, o):
return BirthdayPartyAttached(o)
guests = ListProperty(Person, appendGuest, notify=guests_changed, final=True)
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
from PySide6.QtCore import QTimer, Property, Signal, Slot
from PySide6.QtQml import QmlElement, QPyQmlPropertyValueSource
# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "People"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class HappyBirthdaySong(QPyQmlPropertyValueSource):
name_changed = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.m_target = None
self.m_name = ""
self.m_line = -1
self.m_lyrics = []
self.m_timer = QTimer(self)
self.m_timer.timeout.connect(self.advance)
self.m_timer.start(1000)
def setTarget(self, property):
self.m_target = property
@Property(str, notify=name_changed, final=True)
def name(self):
return self.m_name
@name.setter
def name(self, n):
if self.m_name != n:
self.m_name = n
self.m_lyrics = ["Happy birthday to you,",
"Happy birthday to you,",
f"Happy birthday dear {self.m_name},",
"Happy birthday to you!",
""]
@Slot()
def advance(self):
self.m_line = (self.m_line + 1) % len(self.m_lyrics)
self.m_target.write(self.m_lyrics[self.m_line])
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
from PySide6.QtCore import QObject, Property, Signal
from PySide6.QtQml import QmlAnonymous, QmlElement
# To be used on the @QmlElement decorator
# (QML_IMPORT_MINOR_VERSION is optional)
QML_IMPORT_NAME = "People"
QML_IMPORT_MAJOR_VERSION = 1
@QmlAnonymous
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):
self._shoe_size = s
@QmlElement
class Boy(Person):
def __init__(self, parent=None):
super().__init__(parent)
@QmlElement
class Girl(Person):
def __init__(self, parent=None):
super().__init__(parent)
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import People
BirthdayParty {
HappyBirthdaySong on announcement { name: "Bob Jones" }
onPartyStarted: (time) => { console.log("This party started rockin' at " + time); }
host: Boy {
name: "Bob Jones"
shoe_size: 12
}
Boy {
name: "Leo Hodges"
BirthdayParty.rsvp: "2009-07-06"
}
Boy {
name: "Jack Smith"
}
Girl {
name: "Anne Brown"
BirthdayParty.rsvp: "2009-07-01"
}
}
module People
typeinfo coercion.qmltypes
Main 1.0 Main.qml