diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-06-15 15:49:29 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-06-21 19:24:42 +0200 |
commit | 6036fd0982122dce9f471877417bab6a7c8833dc (patch) | |
tree | a4d58deb708a81f87e0106cb7cf03c8eb0fb3f7b /examples | |
parent | c291841ff1886c081503112cb26d462f820abced (diff) |
CoAP Multicast Discovery example: update the documentation
* Do not use the "Example" word in the title
* Set the proper example category
* Add a note about running the example from QtCreator
* Add a note on how to terminate docker containers after usage
* Update the screenshot to reflect the changes in the UI, switch to
webp format
* Update the documentation about exposing C++ types to QML. Describe
the modern way of doing it.
* Introduce a section about changes to build files.
Task-number: QTBUG-113858
Pick-to: 6.6 6.5
Change-Id: I1ff3cdc4be673affa791a28d5f4641351060b13b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/coap/doc/images/quickmulticastclient.png | bin | 17289 -> 0 bytes | |||
-rw-r--r-- | examples/coap/doc/images/quickmulticastclient.webp | bin | 0 -> 16396 bytes | |||
-rw-r--r-- | examples/coap/doc/quickmulticastclient.qdoc | 166 | ||||
-rw-r--r-- | examples/coap/quickmulticastclient/Main.qml | 6 | ||||
-rw-r--r-- | examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp | 10 | ||||
-rw-r--r-- | examples/coap/quickmulticastclient/qmlcoapmulticastclient.h | 6 |
6 files changed, 122 insertions, 66 deletions
diff --git a/examples/coap/doc/images/quickmulticastclient.png b/examples/coap/doc/images/quickmulticastclient.png Binary files differdeleted file mode 100644 index 3339db1..0000000 --- a/examples/coap/doc/images/quickmulticastclient.png +++ /dev/null diff --git a/examples/coap/doc/images/quickmulticastclient.webp b/examples/coap/doc/images/quickmulticastclient.webp Binary files differnew file mode 100644 index 0000000..f7eb6b4 --- /dev/null +++ b/examples/coap/doc/images/quickmulticastclient.webp diff --git a/examples/coap/doc/quickmulticastclient.qdoc b/examples/coap/doc/quickmulticastclient.qdoc index e1382b6..dbf8063 100644 --- a/examples/coap/doc/quickmulticastclient.qdoc +++ b/examples/coap/doc/quickmulticastclient.qdoc @@ -1,23 +1,26 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \example quickmulticastclient - \title Quick CoAP Multicast Discovery Example + \title Quick CoAP Multicast Discovery + \examplecategory {Connectivity} \ingroup qtcoap-examples \brief Using the CoAP client for a multicast resource discovery with a Qt Quick user interface. - \image quickmulticastclient.png + \image quickmulticastclient.webp - The \e {Quick CoAP Multicast Discovery Example} demonstrates how to register + The \e {Quick CoAP Multicast Discovery} example demonstrates how to register QCoapClient as a QML type and use it in a Qt Quick application for CoAP multicast resource discovery. \note Qt CoAP does not provide a QML API in its current version. However, you can make the C++ classes of the module available to QML as shown in this example. - \section1 Running the Example + \include examples-run.qdocinc + + \section1 Setting Up a CoAP Server To run the example application, you first need to set up and start at least one CoAP server supporting multicast resource discovery. You have the following options: @@ -46,92 +49,123 @@ \note You can run more than one multicast CoAP servers (on the same host or other hosts in the network) by passing a different \c{--name} to the command above. - \section1 Creating a Client and Using It with QML + To terminate the docker container after usage, first obtain the container's + ID by executing the \c {docker ps} command. The output will look like this: - We create the \c QmlCoapMulticastClient class with the QCoapClient class as a - base class: + \badcode + $ docker ps + CONTAINER ID IMAGE + ccaaeae059f1 sokurazy/coap-multicast-test-server:californium.2.0.x + \endcode - \quotefromfile quickmulticastclient/qmlcoapmulticastclient.h - \skipto QmlCoapMulticastClient - \printuntil }; + After that, use this ID to stop the container: - In the main.cpp file, we register the \c QmlCoapMulticastClient class as a QML - type: + \badcode + docker stop <container_id> + \endcode - \quotefromfile quickmulticastclient/main.cpp - \skipto qmlRegisterType - \printline qmlRegisterType + \section1 Exposign C++ Classes to QML - We also register the QtCoap namespace, to be able to use it in QML code: + In this example, you need to expose the \l QCoapResource and \l QCoapClient + classes, as well as the \l {QtCoap Namespace}{QtCoap} namespace, to QML. + To achieve this, create custom wrapper classes and use the special + \l {Defining QML Types from C++}{registration macros}. - \skipto qmlRegisterUncreatableMetaObject - \printto const QUrl + Create the \c QmlCoapResource class as a wrapper around \l QCoapResource. + Use the \l Q_PROPERTY macro to make several properties accessible from + QML. The class does not need to be directly instantiable from QML, so use + the \l QML_ANONYMOUS macro to register it. - Now in the QML code, we can import and use these types: + \snippet quickmulticastclient/qmlcoapmulticastclient.h coap_resource - \quotefromfile quickmulticastclient/main.qml - \dots - \skipto CoapMulticastClient - \printuntil qtcoap.example.namespace - \dots - \skipto CoapMulticastClient - \printto GridLayout - \dots + After that, create the \c QmlCoapMulticastClient class with the + \l QCoapClient class as a base class. Use the \l Q_PROPERTY macro to + expose a custom property, and also create several \l Q_INVOKABLE methods. + Both the property and the invokable methods can be accessed from QML. + Unlike \c QmlCoapResource, you want to be able to create this class from + QML, so use the \l QML_NAMED_ELEMENT macro to register the class in QML. - The \c {QCoapClient::error()} signal triggers the \c onError signal handler of - \c CoapMulticastClient, and the \c {QmlCoapMulticastClient::finished()} signal - triggers the \c onFinished signal handler, to show the request's status in the UI. - Note that we are not using the \c {QCoapClient::finished()} signal directly, - because it takes a \c {QCoapReply} as a parameter (which is not a QML type), and - we are interested only in the error code. + \snippet quickmulticastclient/qmlcoapmulticastclient.h coap_client - In the \c QmlCoapMulticastClient's constructor, we arrange for the - \c {QCoapClient::finished()} signal to be forwarded to the - \c {QmlCoapMulticastClient::finished()} signal: + Finally, register the \l {QtCoap Namespace}{QtCoap} namespace, so that you + can use the enums provided there: - \quotefromfile quickmulticastclient/qmlcoapmulticastclient.cpp - \skipto QmlCoapMulticastClient::QmlCoapMulticastClient - \printto QmlCoapMulticastClient::discover + \snippet quickmulticastclient/qmlcoapmulticastclient.h coap_namespace - When the \uicontrol Discover button is pressed, we invoke one of the overloaded - \c {discover()} methods, based on the selected multicast group: + \section1 Adjusting Build Files - \quotefromfile quickmulticastclient/main.qml - \skipto Button { - \dots - \printto ListModel { + To make the custom types available from QML, update the build system files + accordingly. + + \section2 CMake Build + + For a CMake-based build, add the following to the \c {CMakeLists.txt}: + + \quotefromfile quickmulticastclient/CMakeLists.txt + \skipto qt_add_qml_module + \printuntil ) + + \section2 qmake Build + + For a qmake build, modify the \c {quickmulticastclient.pro} file in the + following way: + + \quotefromfile quickmulticastclient/quickmulticastclient.pro + \skipto CONFIG + \printuntil QML_IMPORT_MAJOR_VERSION \dots + \skipto qml_resources.files + \printuntil RESOURCES + + \section1 Using New QML Types + + Now, when the C++ classes are properly exposed to QML, you can use the new + types: + + \snippet quickmulticastclient/Main.qml client + + The \c {QmlCoapMulticastClient::finished()} signal triggers the + \c onFinished signal handler, to show the request's status in the UI. + Note that the example does not use \l {QCoapClient}'s signals directly, + because both \l {QCoapClient::}{error()} and \l {QCoapClient::}{finished()} + signals take a \l {QCoapReply} as a parameter (which is not exposed to QML), + and the example only requires the error code. + + The \c {QmlCoapMulticastClient}'s constructor forwards the + \l {QCoapClient}'s signals to \c {QmlCoapMulticastClient::finished()} + signal: + + \snippet quickmulticastclient/qmlcoapmulticastclient.cpp ctor + + When the \uicontrol Discover button is pressed, one of the overloaded + \c {discover()} methods is invoked, based on the selected multicast group: + + \snippet quickmulticastclient/Main.qml discover_button This overload is called when a custom multicast group or a host address is selected: - \quotefromfile quickmulticastclient/qmlcoapmulticastclient.cpp - \skipto QmlCoapMulticastClient::discover - \printto QmlCoapMulticastClient::discover(QtCoap::MulticastGroup + \snippet quickmulticastclient/qmlcoapmulticastclient.cpp discover_custom And this overload is called when one of the suggested multicast groups is selected in the UI: - \printto void QmlCoapMulticastClient::onDiscovered + \snippet quickmulticastclient/qmlcoapmulticastclient.cpp discover_group - The \c {QCoapClient::discovered()} signal delivers a list of \c {QCoapResources}, - which is not a QML type. To make the resources available in QML, we forward each - resource in the list to the \c {QmlCoapMulticastClient::discovered()} signal, which - takes a \c QmlCoapResource instead: + The \l {QCoapResourceDiscoveryReply::discovered()} signal delivers a list + of \l {QCoapResource}s, which is not a QML type. To make the resources + available in QML, forward each resource in the list to the + \c {QmlCoapMulticastClient::discovered()} signal, which takes a + \c QmlCoapResource instead: - \printuntil + \snippet quickmulticastclient/qmlcoapmulticastclient.cpp on_discovered - \c QmlCoapResource is a wrapper around QCoapResource, to make some of its - properties available in QML: + The discovered resources are added to the \c resourceModel of the list view in the UI: - \quotefromfile quickmulticastclient/qmlcoapmulticastclient.h - \skipto class QmlCoapResource - \printuntil }; + \snippet quickmulticastclient/Main.qml add_resources - The discovered resources are added to the \c resourceModel of the list view in the UI: + While the discovery is in progress, press the \uicontrol {Stop Discovery} + button to stop the discovery. Internally it is done by aborting the current + request: - \quotefromfile quickmulticastclient/main.qml - \skipto addResource - \dots - \printto CoapMulticastClient { - \dots + \snippet quickmulticastclient/qmlcoapmulticastclient.cpp stop_discovery */ diff --git a/examples/coap/quickmulticastclient/Main.qml b/examples/coap/quickmulticastclient/Main.qml index 08047b1..5be06f2 100644 --- a/examples/coap/quickmulticastclient/Main.qml +++ b/examples/coap/quickmulticastclient/Main.qml @@ -16,12 +16,15 @@ Window { height: 480 title: qsTr("Qt Quick CoAP Multicast Discovery") + //! [add_resources] function addResource(resource) { resourceModel.insert(0, {"host" : resource.host, "path" : resource.path, "title" : resource.title}) } + //! [add_resources] + //! [client] CoapMulticastClient { id: client onDiscovered: (resource) => { root.addResource(resource) } @@ -32,6 +35,7 @@ Window { : qsTr("Resource discovery failed with error code: %1").arg(error) } } + //! [client] GridLayout { anchors.fill: parent @@ -121,6 +125,7 @@ Window { Layout.fillWidth: true } + //! [discover_button] Button { id: discoverButton text: client.isDiscovering ? qsTr("Stop Discovery") : qsTr("Discover") @@ -146,6 +151,7 @@ Window { } } } + //! [discover_button] Button { id: clearButton diff --git a/examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp b/examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp index 5669fb4..9d12c4c 100644 --- a/examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp +++ b/examples/coap/quickmulticastclient/qmlcoapmulticastclient.cpp @@ -8,6 +8,7 @@ Q_LOGGING_CATEGORY(lcCoapClient, "qt.coap.client") +//! [ctor] QmlCoapMulticastClient::QmlCoapMulticastClient(QObject *parent) : QCoapClient(QtCoap::SecurityMode::NoSecurity, parent) { @@ -30,7 +31,9 @@ QmlCoapMulticastClient::QmlCoapMulticastClient(QObject *parent) emit finished(static_cast<int>(err)); }); } +//! [ctor] +//! [discover_custom] void QmlCoapMulticastClient::discover(const QString &host, int port, const QString &discoveryPath) { QUrl url; @@ -46,7 +49,9 @@ void QmlCoapMulticastClient::discover(const QString &host, int port, const QStri qCWarning(lcCoapClient, "Discovery request failed."); } } +//! [discover_custom] +//! [discover_group] void QmlCoapMulticastClient::discover(QtCoap::MulticastGroup group, int port, const QString &discoveryPath) { @@ -59,18 +64,22 @@ void QmlCoapMulticastClient::discover(QtCoap::MulticastGroup group, int port, qCWarning(lcCoapClient, "Discovery request failed."); } } +//! [discover_group] +//! [stop_discovery] void QmlCoapMulticastClient::stopDiscovery() { if (m_reply) m_reply->abortRequest(); } +//! [stop_discovery] bool QmlCoapMulticastClient::isDiscovering() const { return m_reply && !m_reply->isFinished(); } +//! [on_discovered] void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply, const QList<QCoapResource> &resources) { @@ -78,5 +87,6 @@ void QmlCoapMulticastClient::onDiscovered(QCoapResourceDiscoveryReply *reply, for (const auto &resource : resources) emit discovered(resource); } +//! [on_discovered] #include "moc_qmlcoapmulticastclient.cpp" diff --git a/examples/coap/quickmulticastclient/qmlcoapmulticastclient.h b/examples/coap/quickmulticastclient/qmlcoapmulticastclient.h index 79c33ee..2001d03 100644 --- a/examples/coap/quickmulticastclient/qmlcoapmulticastclient.h +++ b/examples/coap/quickmulticastclient/qmlcoapmulticastclient.h @@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE class QCoapResourceDiscoveryReply; QT_END_NAMESPACE +//! [coap_resource] class QmlCoapResource : public QCoapResource { Q_GADGET @@ -29,8 +30,10 @@ public: QString hostStr() const { return host().toString(); } }; +//! [coap_resource] Q_DECLARE_METATYPE(QmlCoapResource) +//! [coap_client] class QmlCoapMulticastClient : public QCoapClient { Q_OBJECT @@ -60,12 +63,15 @@ public slots: private: QCoapResourceDiscoveryReply *m_reply = nullptr; }; +//! [coap_client] +//! [coap_namespace] namespace QCoapForeignNamespace { Q_NAMESPACE QML_FOREIGN_NAMESPACE(QtCoap) QML_NAMED_ELEMENT(QtCoap) } +//! [coap_namespace] #endif // QMLCOAPMULTICASTCLIENT_H |