From 405bd4299819e39397cea0090a9442fd4b6ce911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20De=20Canni=C3=A8re?= Date: Fri, 17 Mar 2023 15:42:47 +0100 Subject: 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 Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- .../CMakeLists.txt | 60 +++++++++ .../advanced7-Foreign-objects-integration/Main.qml | 43 ++++++ .../application.pro | 26 ++++ .../birthdayparty.cpp | 150 +++++++++++++++++++++ .../birthdayparty.h | 90 +++++++++++++ .../foreign.pro | 7 + .../foreign.qrc | 6 + .../foreigndisplay.h | 20 +++ .../happybirthdaysong.cpp | 45 +++++++ .../happybirthdaysong.h | 39 ++++++ .../library/CMakeLists.txt | 17 +++ .../library/ThirdPartyDisplay.cpp | 45 +++++++ .../library/ThirdPartyDisplay.h | 36 +++++ .../library/library.pro | 8 ++ .../advanced7-Foreign-objects-integration/main.cpp | 50 +++++++ .../person.cpp | 87 ++++++++++++ .../advanced7-Foreign-objects-integration/person.h | 87 ++++++++++++ .../qmldir.in | 5 + 18 files changed, 821 insertions(+) create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/CMakeLists.txt create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/Main.qml create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/application.pro create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.cpp create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.h create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.pro create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.qrc create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreigndisplay.h create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.cpp create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.h create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/CMakeLists.txt create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.cpp create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.h create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/library.pro create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/main.cpp create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/person.cpp create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/person.h create mode 100644 examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/qmldir.in (limited to 'examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration') diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/CMakeLists.txt b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/CMakeLists.txt new file mode 100644 index 0000000000..3769b887c0 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(foreign LANGUAGES CXX) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/qml/tutorials/extending-qml-advanced/advanced7-Extension-objects") + +find_package(Qt6 REQUIRED COMPONENTS Core Qml Quick Gui) +qt_standard_project_setup() + +qt_policy(SET QTP0001 NEW) + +add_subdirectory(library/) + +qt_add_executable(foreign + birthdayparty.cpp + birthdayparty.h + foreigndisplay.h + happybirthdaysong.cpp + happybirthdaysong.h + person.cpp + person.h + main.cpp +) + +target_link_libraries(foreign PUBLIC + Qt::Core + Qt::Qml + Qt::Gui + library +) + +set_target_properties(foreign PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_include_directories(foreign PUBLIC + "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/library" +) + +qt_add_qml_module(foreign + URI People + QML_FILES Main.qml + SOURCES foreigndisplay.h + DEPENDENCIES + QtQuick +) + +install(TARGETS foreign + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/Main.qml b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/Main.qml new file mode 100644 index 0000000000..988bea49f8 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/Main.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import People +import QtQuick // For QColor + +BirthdayParty { + id: party + HappyBirthdaySong on announcement { + name: party.host.name + } + + display: ThirdPartyDisplay { + foregroundColor: "black" + backgroundColor: "white" + } + + onPartyStarted: (time) => { console.log("This party started rockin' at " + time); } + + + host: Boy { + name: "Bob Jones" + shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 } + } + + Boy { + name: "Leo Hodges" + BirthdayParty.rsvp: Date.fromLocaleString(Qt.locale(), "2023-03-01", "yyyy-MM-dd") + shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 } + } + Boy { + name: "Jack Smith" + shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 } + } + Girl { + name: "Anne Brown" + BirthdayParty.rsvp: Date.fromLocaleString(Qt.locale(), "2023-03-03", "yyyy-MM-dd") + shoe.size: 7 + shoe.color: "red" + shoe.brand: "Marc Jacobs" + shoe.price: 99.99 + } +} diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/application.pro b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/application.pro new file mode 100644 index 0000000000..b53397d49c --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/application.pro @@ -0,0 +1,26 @@ +TEMPLATE = app + +CONFIG += console + +QT += core qml + +DEPENDPATH += library +INCLUDEPATH += library +LIBS += -Llibrary/ -llibrary + +SOURCES += \ + birthdayparty.cpp \ + happybirthdaysong.cpp \ + main.cpp \ + person.cpp +HEADERS += \ + birthdayparty.h \ + foreigndisplay.h \ + happybirthdaysong.h \ + person.h + +CONFIG += qmltypes +QML_IMPORT_NAME = People +QML_IMPORT_MAJOR_VERSION = 1 + +RESOURCES += foreign.qrc diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.cpp new file mode 100644 index 0000000000..7a9debe195 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.cpp @@ -0,0 +1,150 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "birthdayparty.h" + +QDate BirthdayPartyAttached::rsvp() const +{ + return m_rsvp; +} + +void BirthdayPartyAttached::setRsvp(QDate rsvpDate) +{ + if (m_rsvp != rsvpDate) { + m_rsvp = rsvpDate; + emit rsvpChanged(); + } +} + +Person *BirthdayParty::host() const +{ + return m_host; +} + +void BirthdayParty::setHost(Person *host) +{ + if (m_host != host) { + m_host = host; + emit hostChanged(); + } +} + +QQmlListProperty 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 *list, Person *guest) +{ + static_cast(list->data)->appendGuest(guest); +} + +void BirthdayParty::clearGuests(QQmlListProperty *list) +{ + static_cast(list->data)->clearGuests(); +} + +void BirthdayParty::replaceGuest(QQmlListProperty *list, qsizetype index, Person *guest) +{ + static_cast(list->data)->replaceGuest(index, guest); +} + +void BirthdayParty::removeLastGuest(QQmlListProperty *list) +{ + static_cast(list->data)->removeLastGuest(); +} + +Person *BirthdayParty::guest(QQmlListProperty *list, qsizetype index) +{ + return static_cast(list->data)->guest(index); +} + +qsizetype BirthdayParty::guestCount(QQmlListProperty *list) +{ + return static_cast(list->data)->guestCount(); +} + +void BirthdayParty::startParty() +{ + QDateTime time = QDateTime::currentDateTime(); + emit partyStarted(time); +} + +QString BirthdayParty::announcement() const +{ + return m_announcement; +} + +void BirthdayParty::setAnnouncement(const QString &announcement) +{ + if (m_announcement != announcement) { + m_announcement = announcement; + emit announcementChanged(); + } + m_display->setContent(announcement); +} + +ThirdPartyDisplay *BirthdayParty::display() const +{ + return m_display; +} + +void BirthdayParty::setDisplay(ThirdPartyDisplay *display) +{ + if (m_display != display) { + m_display = display; + emit displayChanged(); + } +} + +BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object) +{ + return new BirthdayPartyAttached(object); +} diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.h b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.h new file mode 100644 index 0000000000..59c53f2484 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/birthdayparty.h @@ -0,0 +1,90 @@ +// 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 "ThirdPartyDisplay.h" + +#include +#include +#include +#include + +#include + +class BirthdayPartyAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp NOTIFY rsvpChanged FINAL) + QML_ANONYMOUS +public: + using QObject::QObject; + + QDate rsvp() const; + void setRsvp(QDate); + +signals: + void rsvpChanged(); + +private: + QDate m_rsvp; +}; + +class BirthdayParty : public QObject +{ + Q_OBJECT + Q_PROPERTY(Person *host READ host WRITE setHost NOTIFY hostChanged FINAL) + Q_PROPERTY(QQmlListProperty guests READ guests NOTIFY guestsChanged FINAL) + Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement NOTIFY announcementChanged FINAL) + Q_PROPERTY(ThirdPartyDisplay *display READ display WRITE setDisplay NOTIFY displayChanged FINAL) + Q_CLASSINFO("DefaultProperty", "guests") + QML_ELEMENT + QML_ATTACHED(BirthdayPartyAttached) +public: + using QObject::QObject; + + Person *host() const; + void setHost(Person *); + + QQmlListProperty guests(); + void appendGuest(Person *); + qsizetype guestCount() const; + Person *guest(qsizetype) const; + void clearGuests(); + void replaceGuest(qsizetype, Person *); + void removeLastGuest(); + + QString announcement() const; + void setAnnouncement(const QString &); + + ThirdPartyDisplay *display() const; + void setDisplay(ThirdPartyDisplay *); + + static BirthdayPartyAttached *qmlAttachedProperties(QObject *); + + void startParty(); + +signals: + void hostChanged(); + void guestsChanged(); + void partyStarted(QDateTime time); + void announcementChanged(); + void displayChanged(); + +private: + static void appendGuest(QQmlListProperty *, Person *); + static qsizetype guestCount(QQmlListProperty *); + static Person *guest(QQmlListProperty *, qsizetype); + static void clearGuests(QQmlListProperty *); + static void replaceGuest(QQmlListProperty *, qsizetype, Person *); + static void removeLastGuest(QQmlListProperty *); + + Person *m_host = nullptr; + QList m_guests; + QString m_announcement; + ThirdPartyDisplay *m_display = nullptr; +}; + +#endif // BIRTHDAYPARTY_H diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.pro b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.pro new file mode 100644 index 0000000000..b637cb0840 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + application.pro \ + library + +application.depends = library diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.qrc b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.qrc new file mode 100644 index 0000000000..b1eeb489e2 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreign.qrc @@ -0,0 +1,6 @@ + + + Main.qml + qmldir.in + + diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreigndisplay.h b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreigndisplay.h new file mode 100644 index 0000000000..ee42ca965c --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/foreigndisplay.h @@ -0,0 +1,20 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef FOREIGNDISPLAY_H +#define FOREIGNDISPLAY_H + +#include "ThirdPartyDisplay.h" + +#include +#include +#include + +class ForeignDisplay : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(ThirdPartyDisplay) + QML_FOREIGN(ThirdPartyDisplay) +}; + +#endif // FOREIGNDISPLAY_H diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.cpp new file mode 100644 index 0000000000..7a756a4a71 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "happybirthdaysong.h" + +#include + +HappyBirthdaySong::HappyBirthdaySong(QObject *parent) : QObject(parent) +{ + auto *timer = new QTimer(this); + QObject::connect(timer, &QTimer::timeout, this, &HappyBirthdaySong::advance); + timer->start(1000); +} + +void HappyBirthdaySong::setTarget(const QQmlProperty &target) +{ + m_target = target; +} + +QString HappyBirthdaySong::name() const +{ + return m_name; +} + +void HappyBirthdaySong::setName(const QString &name) +{ + if (m_name != name) { + m_name = name; + emit nameChanged(); + } + + m_lyrics.clear(); + m_lyrics << "Happy birthday to you,"; + m_lyrics << "Happy birthday to you,"; + m_lyrics << "Happy birthday dear " + m_name + ","; + m_lyrics << "Happy birthday to you!"; + m_lyrics << ""; +} + +void HappyBirthdaySong::advance() +{ + m_line = (m_line + 1) % m_lyrics.count(); + + m_target.write(m_lyrics.at(m_line)); +} diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.h b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.h new file mode 100644 index 0000000000..f87521a760 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/happybirthdaysong.h @@ -0,0 +1,39 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef HAPPYBIRTHDAYSONG_H +#define HAPPYBIRTHDAYSONG_H + +#include +#include +#include +#include + +class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource +{ + Q_OBJECT + Q_INTERFACES(QQmlPropertyValueSource) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) + QML_ELEMENT +public: + explicit HappyBirthdaySong(QObject *parent = nullptr); + + void setTarget(const QQmlProperty &) override; + + QString name() const; + void setName(const QString &); + +signals: + void nameChanged(); + +private slots: + void advance(); + +private: + qsizetype m_line = -1; + QStringList m_lyrics; + QQmlProperty m_target; + QString m_name; +}; + +#endif // HAPPYBIRTHDAYSONG_H diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/CMakeLists.txt b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/CMakeLists.txt new file mode 100644 index 0000000000..5b4528a340 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) + +project(library) + +add_library(library ThirdPartyDisplay.cpp ThirdPartyDisplay.h) + +qt_extract_metatypes(library) + +target_link_libraries(library PUBLIC + Qt::Core + Qt::Qml + Qt::Quick + Qt::Gui +) diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.cpp new file mode 100644 index 0000000000..5fc4eb2e8f --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "ThirdPartyDisplay.h" +#include + +const QString &ThirdPartyDisplay::content() const +{ + return m_content; +} + +void ThirdPartyDisplay::setContent(const QString &content) +{ + if (m_content != content) { + m_content = content; + emit contentChanged(); + } + qInfo() << QStringLiteral("[Fancy ThirdPartyDisplay] ") + content; +} + +QColor ThirdPartyDisplay::foregroundColor() const +{ + return m_foregroundColor; +} + +void ThirdPartyDisplay::setForegroundColor(QColor color) +{ + if (m_foregroundColor != color) { + m_foregroundColor = color; + emit colorsChanged(); + } +} + +QColor ThirdPartyDisplay::backgroundColor() const +{ + return m_backgroundColor; +} + +void ThirdPartyDisplay::setBackgroundColor(QColor color) +{ + if (m_backgroundColor != color) { + m_backgroundColor = color; + emit colorsChanged(); + } +} diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.h b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.h new file mode 100644 index 0000000000..525c9f72cf --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/ThirdPartyDisplay.h @@ -0,0 +1,36 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef THIRDPARTYDISPLAY_H +#define THIRDPARTYDISPLAY_H + +#include +#include + +class Q_DECL_EXPORT ThirdPartyDisplay : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString content READ content WRITE setContent NOTIFY contentChanged FINAL) + Q_PROPERTY(QColor foregroundColor READ foregroundColor WRITE setForegroundColor NOTIFY colorsChanged FINAL) + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY colorsChanged FINAL) +public: + const QString &content() const; + void setContent(const QString &content); + + QColor foregroundColor() const; + void setForegroundColor(QColor); + + QColor backgroundColor() const; + void setBackgroundColor(QColor); + +signals: + void contentChanged(); + void colorsChanged(); + +private: + QString m_content; + QColor m_foregroundColor; + QColor m_backgroundColor; +}; + +#endif // THIRDPARTYDISPLAY_H diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/library.pro b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/library.pro new file mode 100644 index 0000000000..f7009c46c9 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/library/library.pro @@ -0,0 +1,8 @@ +TEMPLATE = lib + +CONFIG += static + +SOURCES += ThirdPartyDisplay.cpp +HEADERS += ThirdPartyDisplay.h + +QT += core qml gui diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/main.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/main.cpp new file mode 100644 index 0000000000..9c6f6bcc2f --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/main.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "birthdayparty.h" +#include "person.h" + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadFromModule("People", "Main"); + std::unique_ptr party{ qobject_cast(component.create()) }; + + if (party && party->host()) { + qInfo() << party->host()->name() << "is having a birthday!"; + + if (qobject_cast(party->host())) + qInfo() << "He is inviting:"; + else + qInfo() << "She is inviting:"; + + for (qsizetype ii = 0; ii < party->guestCount(); ++ii) { + Person *guest = party->guest(ii); + + QDate rsvpDate; + QObject *attached = qmlAttachedPropertiesObject(guest, false); + if (attached) + rsvpDate = attached->property("rsvp").toDate(); + + if (rsvpDate.isNull()) + qInfo() << " " << guest->name() << "RSVP date: Hasn't RSVP'd"; + else + qInfo() << " " << guest->name() << "RSVP date:" << rsvpDate.toString(); + } + + party->startParty(); + return QCoreApplication::exec(); + } + + qWarning() << component.errors(); + return EXIT_FAILURE; +} diff --git a/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/person.cpp b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/person.cpp new file mode 100644 index 0000000000..fe3d19b58d --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/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/advanced7-Foreign-objects-integration/person.h b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/person.h new file mode 100644 index 0000000000..0ed76223ba --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/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 +#include +#include + +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/advanced7-Foreign-objects-integration/qmldir.in b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/qmldir.in new file mode 100644 index 0000000000..5289a31938 --- /dev/null +++ b/examples/qml/tutorials/extending-qml-advanced/advanced7-Foreign-objects-integration/qmldir.in @@ -0,0 +1,5 @@ +module People +typeinfo foreign.qmltypes +prefer :/qt/qml/People/ +Main 254.0 Main.qml +depends QtQuick -- cgit v1.2.1