扩展QML(高级) - 分组属性

这是使用生日派对示例来展示QML一些高级功能的6个示例系列中的第四个。

需要更多关于客人鞋子的信息。除了他们的尺寸,我们还想存储鞋子的颜色、品牌和价格。这些信息存储在ShoeDescription类中。

14
15@QmlAnonymous
16class ShoeDescription(QObject):
17    brand_changed = Signal()
18    size_changed = Signal()
19    price_changed = Signal()
20    color_changed = Signal()
21
22    def __init__(self, parent=None):
23        super().__init__(parent)
24        self._brand = ''
25        self._size = 0
26        self._price = 0
27        self._color = QColor()
28
29    @Property(str, notify=brand_changed, final=True)
30    def brand(self):
31        return self._brand
32
33    @brand.setter
34    def brand(self, b):
35        if self._brand != b:
36            self._brand = b
37            self.brand_changed.emit()
38
39    @Property(int, notify=size_changed, final=True)
40    def size(self):
41        return self._size
42
43    @size.setter
44    def size(self, s):
45        if self._size != s:
46            self._size = s
47            self.size_changed.emit()
48
49    @Property(float, notify=price_changed, final=True)
50    def price(self):
51        return self._price
52
53    @price.setter
54    def price(self, p):
55        if self._price != p:
56            self._price = p
57            self.price_changed.emit()
58
59    @Property(QColor, notify=color_changed, final=True)
60    def color(self):
61        return self._color
62
63    @color.setter
64    def color(self, c):
65        if self._color != c:
66            self._color = c

每个人现在有两个属性,一个name和一个鞋子描述shoe

69
70@QmlAnonymous
71class Person(QObject):
72    name_changed = Signal()
73
74    def __init__(self, parent=None):
75        super().__init__(parent)
76        self._name = ''
77        self._shoe = ShoeDescription()
78
79    @Property(str, notify=name_changed, final=True)
80    def name(self):
81        return self._name
82
83    @name.setter
84    def name(self, n):
85        if self._name != n:
86            self._name = n
87            self.name_changed.emit()
88
89    @Property(ShoeDescription, final=True)
90    def shoe(self):

为鞋子描述的每个元素指定值是可行的,但有点重复。

26    Girl {
27        name: "Anne Brown"
28        shoe.size: 7
29        shoe.color: "red"
30        shoe.brand: "Job Macobs"
31        shoe.price: 699.99
32    }

分组属性提供了一种更优雅的方式来分配这些属性。 与逐个为每个属性赋值不同,可以将各个值作为一组传递给shoe属性,使代码更具可读性。无需进行任何更改即可启用此功能,因为它默认适用于所有QML。

 9    host: Boy {
10        name: "Bob Jones"
11        shoe { size: 12; color: "white"; brand: "Bikey"; price: 90.0 }
12    }

下载 这个 示例

# 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/advanced4-Grouped-properties 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 Boy, Girl  # noqa: F401
from birthdayparty import BirthdayParty  # noqa: F401


if __name__ == '__main__':
    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:")
    best_shoe = None
    for g in range(party.guestCount()):
        guest = party.guest(g)
        name = guest.name
        print(f"    {name}")
        if not best_shoe or best_shoe.shoe.price < guest.shoe.price:
            best_shoe = guest
    if best_shoe:
        print(f"{best_shoe.name} is wearing the best shoes!")
    del engine
    sys.exit(0)
# 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, ClassInfo, 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
@ClassInfo(DefaultProperty="guests")
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) 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.QtGui import QColor
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 ShoeDescription(QObject):
    brand_changed = Signal()
    size_changed = Signal()
    price_changed = Signal()
    color_changed = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self._brand = ''
        self._size = 0
        self._price = 0
        self._color = QColor()

    @Property(str, notify=brand_changed, final=True)
    def brand(self):
        return self._brand

    @brand.setter
    def brand(self, b):
        if self._brand != b:
            self._brand = b
            self.brand_changed.emit()

    @Property(int, notify=size_changed, final=True)
    def size(self):
        return self._size

    @size.setter
    def size(self, s):
        if self._size != s:
            self._size = s
            self.size_changed.emit()

    @Property(float, notify=price_changed, final=True)
    def price(self):
        return self._price

    @price.setter
    def price(self, p):
        if self._price != p:
            self._price = p
            self.price_changed.emit()

    @Property(QColor, notify=color_changed, final=True)
    def color(self):
        return self._color

    @color.setter
    def color(self, c):
        if self._color != c:
            self._color = c
            self.color_changed.emit()


@QmlAnonymous
class Person(QObject):
    name_changed = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self._name = ''
        self._shoe = ShoeDescription()

    @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(ShoeDescription, final=True)
    def shoe(self):
        return self._shoe


@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 QtQuick

import People

BirthdayParty {
    host: Boy {
        name: "Bob Jones"
        shoe { size: 12; color: "white"; brand: "Bikey"; price: 90.0 }
    }

    Boy {
        name: "Leo Hodges"
        shoe { size: 10; color: "black"; brand: "Thebok"; price: 59.95 }
    }
    Boy { name: "Jack Smith"
        shoe {
            size: 8
            color: "blue"
            brand: "Luma"
            price: 19.95
        }
    }
    Girl {
        name: "Anne Brown"
        shoe.size: 7
        shoe.color: "red"
        shoe.brand: "Job Macobs"
        shoe.price: 699.99
    }
}
module People
typeinfo coercion.qmltypes
Main 1.0 Main.qml