扩展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() 函数用于定义此源作用于哪个属性。在这种情况下,值源写入 BirthdayPartyannouncement 属性,以随时间显示歌词。它有一个内部计时器,导致聚会的 announcement 属性被重复设置为歌词的下一行。

在QML中,HappyBirthdaySongBirthdayParty中被实例化。 其签名中的on关键字用于指定值源所针对的属性,在本例中为announcementHappyBirthdaySong对象的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