summaryrefslogtreecommitdiff
path: root/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2023-03-17 15:42:47 +0100
committerOlivier De Cannière <olivier.decanniere@qt.io>2023-03-30 18:02:16 +0200
commit405bd4299819e39397cea0090a9442fd4b6ce911 (patch)
treec1254e18a8ab47cc6bde048eb52ad0d89c2492c8 /examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties
parent03ff348b4942ae29dd5bc2bd563998d7ba82ecd7 (diff)
downloadqtdeclarative-405bd4299819e39397cea0090a9442fd4b6ce911.tar.gz
Doc: Revamp "Extending QML" examples into a tutorial
The examples in the "Extending QML" series were often redundant with the information of the "Writing QML Extensions with C++" tutorial, had outdated code and sometimes had no documentation. The examples that covered topics not mentioned in the first tutorial were revamped into a second "advanced" tutorial extending the first one. The others were removed. The remaining examples were largely based on the same example code of a birthday party. This code was slightly adapted and separated into 7 states, each building upon the previous, with the code change illustrating the associated feature. A tutorial page, in the style of the first one, was added documenting the different QML features and the required code changes in the example project. Links in the documentation from and to the affected pages were update as best as possible. Pick-to: 6.5 Fixes: QTBUG-111033 Change-Id: I9d97e8b32b128c1624d67525996fa14d493909d3 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties')
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/CMakeLists.txt46
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml33
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.cpp99
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.h49
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.pro12
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.qrc6
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/main.cpp45
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.cpp87
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h87
-rw-r--r--examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/qmldir.in5
10 files changed, 469 insertions, 0 deletions
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/CMakeLists.txt b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/CMakeLists.txt
new file mode 100644
index 0000000000..89aff6402f
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(grouped LANGUAGES CXX)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Qml Gui)
+qt_standard_project_setup()
+
+qt_policy(SET QTP0001 NEW)
+
+qt_add_executable(grouped
+ birthdayparty.cpp birthdayparty.h
+ main.cpp
+ person.cpp person.h
+)
+
+set_target_properties(grouped PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(grouped PUBLIC
+ Qt::Core
+ Qt::Qml
+ Qt::Gui
+)
+
+qt_add_qml_module(grouped
+ URI People
+ QML_FILES Main.qml
+ DEPENDENCIES
+ QtQuick
+)
+
+install(TARGETS grouped
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml
new file mode 100644
index 0000000000..27951b5ea8
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/Main.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import People
+import QtQuick // For QColor
+
+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: 99.99
+ }
+}
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.cpp
new file mode 100644
index 0000000000..ad38f284e7
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.cpp
@@ -0,0 +1,99 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "birthdayparty.h"
+
+Person *BirthdayParty::host() const
+{
+ return m_host;
+}
+
+void BirthdayParty::setHost(Person *host)
+{
+ if (m_host != host) {
+ m_host = host;
+ emit hostChanged();
+ }
+}
+
+QQmlListProperty<Person> BirthdayParty::guests()
+{
+ return { this,
+ this,
+ &BirthdayParty::appendGuest,
+ &BirthdayParty::guestCount,
+ &BirthdayParty::guest,
+ &BirthdayParty::clearGuests,
+ &BirthdayParty::replaceGuest,
+ &BirthdayParty::removeLastGuest };
+}
+
+void BirthdayParty::appendGuest(Person *guest)
+{
+ m_guests.append(guest);
+ emit guestsChanged();
+}
+
+qsizetype BirthdayParty::guestCount() const
+{
+ return m_guests.count();
+}
+
+Person *BirthdayParty::guest(qsizetype index) const
+{
+ return m_guests.at(index);
+}
+
+void BirthdayParty::clearGuests()
+{
+ if (!m_guests.empty()) {
+ m_guests.clear();
+ emit guestsChanged();
+ }
+}
+
+void BirthdayParty::replaceGuest(qsizetype index, Person *guest)
+{
+ if (m_guests.size() > index) {
+ m_guests[index] = guest;
+ emit guestsChanged();
+ }
+}
+
+void BirthdayParty::removeLastGuest()
+{
+ if (!m_guests.empty()) {
+ m_guests.removeLast();
+ emit guestsChanged();
+ }
+}
+
+void BirthdayParty::appendGuest(QQmlListProperty<Person> *list, Person *guest)
+{
+ static_cast<BirthdayParty *>(list->data)->appendGuest(guest);
+}
+
+void BirthdayParty::clearGuests(QQmlListProperty<Person> *list)
+{
+ static_cast<BirthdayParty *>(list->data)->clearGuests();
+}
+
+void BirthdayParty::replaceGuest(QQmlListProperty<Person> *list, qsizetype index, Person *guest)
+{
+ static_cast<BirthdayParty *>(list->data)->replaceGuest(index, guest);
+}
+
+void BirthdayParty::removeLastGuest(QQmlListProperty<Person> *list)
+{
+ static_cast<BirthdayParty *>(list->data)->removeLastGuest();
+}
+
+Person *BirthdayParty::guest(QQmlListProperty<Person> *list, qsizetype index)
+{
+ return static_cast<BirthdayParty *>(list->data)->guest(index);
+}
+
+qsizetype BirthdayParty::guestCount(QQmlListProperty<Person> *list)
+{
+ return static_cast<BirthdayParty *>(list->data)->guestCount();
+}
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.h b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.h
new file mode 100644
index 0000000000..4d7e61a487
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/birthdayparty.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef BIRTHDAYPARTY_H
+#define BIRTHDAYPARTY_H
+
+#include "person.h"
+
+#include <QObject>
+#include <QQmlListProperty>
+
+class BirthdayParty : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Person *host READ host WRITE setHost NOTIFY hostChanged FINAL)
+ Q_PROPERTY(QQmlListProperty<Person> guests READ guests NOTIFY guestsChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "guests")
+ QML_ELEMENT
+public:
+ using QObject::QObject;
+
+ Person *host() const;
+ void setHost(Person *);
+
+ QQmlListProperty<Person> guests();
+ void appendGuest(Person *);
+ qsizetype guestCount() const;
+ Person *guest(qsizetype) const;
+ void clearGuests();
+ void replaceGuest(qsizetype, Person *);
+ void removeLastGuest();
+
+signals:
+ void hostChanged();
+ void guestsChanged();
+
+private:
+ static void appendGuest(QQmlListProperty<Person> *list, Person *);
+ static qsizetype guestCount(QQmlListProperty<Person> *);
+ static Person *guest(QQmlListProperty<Person> *, qsizetype);
+ static void clearGuests(QQmlListProperty<Person> *);
+ static void replaceGuest(QQmlListProperty<Person> *, qsizetype, Person *);
+ static void removeLastGuest(QQmlListProperty<Person> *);
+
+ Person *m_host = nullptr;
+ QList<Person *> m_guests;
+};
+
+#endif // BIRTHDAYPARTY_H
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.pro b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.pro
new file mode 100644
index 0000000000..52e2937edf
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.pro
@@ -0,0 +1,12 @@
+QT += qml
+
+CONFIG += qmltypes
+QML_IMPORT_NAME = People
+QML_IMPORT_MAJOR_VERSION = 1
+
+SOURCES += main.cpp \
+ person.cpp \
+ birthdayparty.cpp
+HEADERS += person.h \
+ birthdayparty.h
+RESOURCES += grouped.qrc
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.qrc b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.qrc
new file mode 100644
index 0000000000..b1eeb489e2
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/grouped.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/qt/qml/People/">
+ <file>Main.qml</file>
+ <file alias="qmldir">qmldir.in</file>
+</qresource>
+</RCC>
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/main.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/main.cpp
new file mode 100644
index 0000000000..0721d496f0
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/main.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "birthdayparty.h"
+#include "person.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QQmlComponent>
+#include <QQmlEngine>
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadFromModule("People", "Main");
+ std::unique_ptr<BirthdayParty> party{ qobject_cast<BirthdayParty *>(component.create()) };
+
+ if (party && party->host()) {
+ qInfo() << party->host()->name() << "is having a birthday!";
+
+ if (qobject_cast<Boy *>(party->host()))
+ qInfo() << "He is inviting:";
+ else
+ qInfo() << "She is inviting:";
+
+ Person *bestShoe = nullptr;
+ for (qsizetype ii = 0; ii < party->guestCount(); ++ii) {
+ Person *guest = party->guest(ii);
+ qInfo() << " " << guest->name();
+
+ if (!bestShoe || bestShoe->shoe()->price() < guest->shoe()->price())
+ bestShoe = guest;
+ }
+ if (bestShoe)
+ qInfo() << bestShoe->name() << "is wearing the best shoes!";
+
+ return EXIT_SUCCESS;
+ }
+
+ qWarning() << component.errors();
+ return EXIT_FAILURE;
+}
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.cpp
new file mode 100644
index 0000000000..fe3d19b58d
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.cpp
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "person.h"
+
+Person::Person(QObject *parent) : QObject(parent)
+{
+ m_shoe = new ShoeDescription(this);
+}
+
+int ShoeDescription::size() const
+{
+ return m_size;
+}
+
+void ShoeDescription::setSize(int size)
+{
+ if (m_size != size) {
+ m_size = size;
+ emit shoeChanged();
+ }
+}
+
+QColor ShoeDescription::color() const
+{
+ return m_color;
+}
+
+void ShoeDescription::setColor(const QColor &color)
+{
+ if (m_color != color) {
+ m_color = color;
+ emit shoeChanged();
+ }
+}
+
+QString ShoeDescription::brand() const
+{
+ return m_brand;
+}
+
+void ShoeDescription::setBrand(const QString &brand)
+{
+ if (m_brand != brand) {
+ m_brand = brand;
+ emit shoeChanged();
+ }
+}
+
+qreal ShoeDescription::price() const
+{
+ return m_price;
+}
+
+void ShoeDescription::setPrice(qreal price)
+{
+ if (m_price != price) {
+ m_price = price;
+ emit shoeChanged();
+ }
+}
+
+QString Person::name() const
+{
+ return m_name;
+}
+
+void Person::setName(const QString &name)
+{
+ if (m_name != name) {
+ m_name = name;
+ emit nameChanged();
+ }
+}
+
+ShoeDescription *Person::shoe() const
+{
+ return m_shoe;
+}
+
+void Person::setShoe(ShoeDescription *shoe)
+{
+ if (m_shoe != shoe) {
+ m_shoe = shoe;
+ emit shoeChanged();
+ }
+}
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h
new file mode 100644
index 0000000000..ecb4545097
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/person.h
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef PERSON_H
+#define PERSON_H
+
+#include <QtQml/qqml.h>
+#include <QColor>
+#include <QObject>
+
+class ShoeDescription : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int size READ size WRITE setSize NOTIFY shoeChanged FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY shoeChanged FINAL)
+ Q_PROPERTY(QString brand READ brand WRITE setBrand NOTIFY shoeChanged FINAL)
+ Q_PROPERTY(qreal price READ price WRITE setPrice NOTIFY shoeChanged FINAL)
+ QML_ANONYMOUS
+public:
+ using QObject::QObject;
+
+ int size() const;
+ void setSize(int);
+
+ QColor color() const;
+ void setColor(const QColor &);
+
+ QString brand() const;
+ void setBrand(const QString &);
+
+ qreal price() const;
+ void setPrice(qreal);
+
+signals:
+ void shoeChanged();
+
+private:
+ int m_size = 0;
+ QColor m_color;
+ QString m_brand;
+ qreal m_price = 0;
+};
+
+class Person : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
+ Q_PROPERTY(ShoeDescription *shoe READ shoe WRITE setShoe NOTIFY shoeChanged FINAL)
+ QML_ELEMENT
+ QML_UNCREATABLE("Person is an abstract base class.")
+public:
+ using QObject::QObject;
+
+ Person(QObject *parent = nullptr);
+
+ QString name() const;
+ void setName(const QString &);
+
+ ShoeDescription *shoe() const;
+ void setShoe(ShoeDescription *shoe);
+
+signals:
+ void nameChanged();
+ void shoeChanged();
+
+private:
+ QString m_name;
+ ShoeDescription *m_shoe = nullptr;
+};
+
+class Boy : public Person
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ using Person::Person;
+};
+
+class Girl : public Person
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ using Person::Person;
+};
+
+#endif // PERSON_H
diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/qmldir.in b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/qmldir.in
new file mode 100644
index 0000000000..2e634e41af
--- /dev/null
+++ b/examples/qml/tutorials/extending-qml-advanced/advanced4-Grouped-properties/qmldir.in
@@ -0,0 +1,5 @@
+module People
+typeinfo grouped.qmltypes
+prefer :/qt/qml/People/
+Main 254.0 Main.qml
+depends QtQuick