diff options
| author | Sami Shalayel <sami.shalayel@qt.io> | 2025-02-18 16:34:19 +0100 |
|---|---|---|
| committer | Sami Shalayel <sami.shalayel@qt.io> | 2025-03-07 14:24:58 +0000 |
| commit | 3d18d15d382d1f020920236c9370789e6ccf1f39 (patch) | |
| tree | fda2946c42c3876fc6c7ff81cb6c421a314bddb5 | |
| parent | 7b4837d3e34a206ccbd3b921e65f1401b09066ee (diff) | |
doc: document how to write modern QML Modules
Add two documents on how to write modern QML Modules, one for porting to
qt_add_qml_module and one for modernizing QML Modules created with
qt_add_qml_module.
Fixes: QTBUG-133547
Change-Id: Ieb1f23d6600b17bfa8a949633e1e9192004804d0
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
(cherry picked from commit 45f024c54086eed57851725932168dc8cd7bd633)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 16296160b2663d2d167374ff219aa499272886b1)
(cherry picked from commit 36375f88409bcf839efa6fdf66ee3f586342ad54)
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
| -rw-r--r-- | src/qml/doc/src/qt6-changes.qdoc | 2 | ||||
| -rw-r--r-- | src/qml/doc/src/qt6-modernize-qml-modules.qdoc | 95 | ||||
| -rw-r--r-- | src/qml/doc/src/qt6-port-to-qt-add-qml-module.qdoc | 188 |
3 files changed, 284 insertions, 1 deletions
diff --git a/src/qml/doc/src/qt6-changes.qdoc b/src/qml/doc/src/qt6-changes.qdoc index 92f78c0e88..1deff94f59 100644 --- a/src/qml/doc/src/qt6-changes.qdoc +++ b/src/qml/doc/src/qt6-changes.qdoc @@ -257,5 +257,5 @@ \endlist - + \sa {Modern QML modules}, {Port QML modules to CMake} */ diff --git a/src/qml/doc/src/qt6-modernize-qml-modules.qdoc b/src/qml/doc/src/qt6-modernize-qml-modules.qdoc new file mode 100644 index 0000000000..cc21f2b9bc --- /dev/null +++ b/src/qml/doc/src/qt6-modernize-qml-modules.qdoc @@ -0,0 +1,95 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! +\page qt6-modernize-qml-modules.html +\title Modern QML modules +\brief Modernize your QML modules. + +QML modules have become more powerful and easier to use in Qt 6. +The following sections describe how to modernize QML modules that already use \l qt_add_qml_module. + +See also \l{Port QML modules to CMake} on how to port a QML module to the +\l qt_add_qml_module CMake API. + +\section1 Use qt_standard_project_setup +\l qt_standard_project_setup sets up \l{Qt CMake policies} needed for modern QML modules, among +other things. To modernize your QML module and follow best practices, call +\l qt_standard_project_setup in the project's top-level \c CMakeLists.txt file before any +\l qt_add_qml_module call: +\badcode +qt_standard_project_setup(REQUIRES 6.8) +\endcode + +\section1 Use the new standard resource path prefix +The standard resource path for QML modules moved from \c{:/} to \c{:/qt/qml} with \l{QTP0001}. Don't +use custom resource prefixes nor extend import paths in the engine. +Remove all \c RESOURCE_PREFIX arguments from all \l qt_add_qml_module calls, as well as all calls to +\l{QQmlEngine::addImportPath} or similar. +Change all qrc paths in your C++ and QML code to use the new resource path prefix: +\badcode +// C++ usages like: +QUrl someUrl("qrc:/MyQmlModule/MyResource1.png"); +// need to be changed to +QUrl someUrl("qrc:/qt/qml/MyQmlModule/MyResource1.png"); + +// QML usages like: +":/MyQmlModule/MyResource1.png" +// need to be changed to +":/qt/qml/MyQmlModule/MyResource1.png" +\endcode + +See also \l{Using the Qt Resource System with QML}. + +\section1 Use loadFromModule to load your QML files + +With the default import path, you can use the \c loadFromModule methods, like \l +QQmlApplicationEngine::loadFromModule, \l QQuickView::loadFromModule, or +\l QQmlComponent::loadFromModule, for example. + +Use \c loadFromModule to load your QML file, for example: +\badcode +engine.load(QUrl(QStringLiteral("qrc:/MyQmlModule/Main.qml"))); +// becomes +engine.loadFromModule("MyQmlModule", "Main"); +\endcode + +\section1 Replace OUTPUT_DIRECTORY and IMPORT_PATH with DEPENDENCIES TARGET +Avoid setting an \c IMPORT_PATH in the \l qt_add_qml_module. Instead, use \c{DEPENDENCIES TARGET} +to declare dependencies to other QML modules that can't be found in the current import path. + +Using \c{DEPENDENCIES TARGET} also eliminates the need for the \c QT_QML_OUTPUT_DIRECTORY CMake +variable and the \c OUTPUT_DIRECTORY argument to \l qt_add_qml_module, so remove their +definitions and usages. + +For example: +\badcode +### in the CMakeLists.txt file defining the dependent QML module: +# don't set QT_QML_OUTPUT_DIRECTORY and remove lines like these: +set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/qml) + +qt_add_qml_module(MyThirdPartyQmlLibraryDependency + URI MyThirdPartyQmlLibraryDependency + .... + # custom output paths are obsolete due to DEPENDENCIES TARGET below, so remove: + OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/qml +} + +### in the CMakeLists.txt file defining the QML module that uses the dependency: +qt_add_qml_module(MyQmlLibrary + URI MyQmlModule + ... + # replace import paths like these: + IMPORT_PATH ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/qml + # with: + DEPENDENCIES TARGET MyThirdPartyQmlLibraryDependency +} +\endcode + +\note You might need to call \c{add_subdirectory()} before calling \l qt_add_qml_module in your +CMakeLists.txt for \c {DEPENDENCIES TARGET} to find the target. + +For more information on how to declare module dependencies, see \l{Declaring module dependencies}. + +\sa {Changes to Qt QML}, {Port QML modules to CMake} +*/ diff --git a/src/qml/doc/src/qt6-port-to-qt-add-qml-module.qdoc b/src/qml/doc/src/qt6-port-to-qt-add-qml-module.qdoc new file mode 100644 index 0000000000..97c1f0d916 --- /dev/null +++ b/src/qml/doc/src/qt6-port-to-qt-add-qml-module.qdoc @@ -0,0 +1,188 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! +\page qt6-port-to-qt-add-qml-module.html +\title Port QML modules to CMake +\brief Port your QML modules to the qt_add_qml_module CMake API. + +QML modules have become more powerful and easier to use in Qt 6. The following sections describe +how to port QML modules to the \l qt_add_qml_module CMake API. + +See also \l{Modern QML modules} on how to modernize a QML module that already uses \l +qt_add_qml_module. + +\section1 Identify issues to fix + +Use \l qmllint to support you through the process. + +Each QML module defined with \l qt_add_qml_module has a \c{_qmllint} CMake target that you can +use to identify potential issues or improvements. For a QML module called \c MyQmlLibrary use +\c{MyQmlLibrary_qmllint}, for example. To run \l qmllint on all QML modules, use \c +{all_qmllint}. + +The warning categories of \l qmllint that hint at QML module issues are: +\list + \li \l{Warnings occurred while importing}{[import]} + \li \l{Unused imports}{[unused-imports]} + \li \l{Unresolved type}{[unresolved-type]} + \li \l{Unresolved Alias}{[unresolved-alias]} + \li \l{Missing enum entry}{[missing-enum-entry]} + \li \l{Missing property}{[missing-property]} + \li \l{Missing type}{[missing-type]} +\endlist + +\section1 Prepare the project for qt_add_qml_module + +\section2 Make qt_add_qml_module available in CMake + +To make \l qt_add_qml_module available in CMake, add \c Core and \c Qml to your \c find_package +call in the project's top-level \c CMakeLists.txt file: +\badcode +find_package(Qt6 REQUIRED COMPONENTS Core Qml) +\endcode + +\section2 Use qt_standard_project_setup + +\l qt_standard_project_setup sets up \l{Qt CMake policies} needed for \l qt_add_qml_module, among +other things. + +Call \l qt_standard_project_setup in the project's top-level \c CMakeLists.txt file +before any \l qt_add_qml_module call: +\badcode +qt_standard_project_setup(REQUIRES 6.8) +\endcode + +\section1 Use qt_add_qml_module + +\l qt_add_qml_module is the CMake function that takes care of generating QML modules. It +automatically generates \c qmldir and \c qmltypes files, and sets up tooling like \l qmlcachegen +or \l qmllint. + +QML modules can be added to both executable and library targets in CMake. QML modules attached +to the executable target can't be used or linked by other executables, while QML modules attached +to library targets can. + +\section2 Add a QML module to your executable target +In this case, the source files of the QML module are treated as part of the executable itself, +rather than being compiled into a separate library. This means neither a module nor plugin library +for this module is created—--the module is fully integrated into the executable. As a result, the +module is tied to that specific program and cannot be reused by other executables or libraries. + +To add a QML module to your executable, in your \c CMakeLists.txt: +\badcode +# pre-existing: +qt_add_executable(MyApp main.cpp) + +# add this +qt_add_qml_module(MyApp + URI MyAppModule + QML_FILES + Main.qml # and possibly more .qml files +) +\endcode + +The \c Main.qml should start with an upper case letter so that it can be instantiated by +\c loadFromModule methods like \l{QQmlApplicationEngine::loadFromModule} or +\l{QQmlComponent::loadFromModule}. +Also, the QML module URI should be different from the target name to avoid name clashes +in the build folder. + +\section2 Add a QML module to your library target +To add a QML module to your library, in your \c CMakeLists.txt: +\badcode +qt_add_qml_module(MyQmlLibrary + URI MyQmlModule + QML_FILES MyQmlComponent1.qml MyQmlComponent2.qml... + SOURCES MyCppComponent1.h MyCppComponent1.cpp MyCppComponent2.h MyCppComponent2.cpp... + RESOURCES MyResource1.png MyResource2.png... +) +\endcode + +\l qt_add_qml_module creates a \c SHARED library via \l qt_add_library if the \c +MyQmlLibrary target does not exist yet, like in this example. + +\note Your QML module URI should be different from the target name to avoid name clashes in the +build folder. + +\section1 Use loadFromModule to load your QML files + +Use \c loadFromModule to load your QML file, for example: +\badcode +engine.load(QUrl(QStringLiteral("qrc:/MyQmlModule/Main.qml"))); +// becomes +engine.loadFromModule("MyQmlModule", "Main"); +\endcode + +\section1 Remove handwritten qmldir files + +\l qt_add_qml_module automatically generates \c qmldir files. If you have singletons in +your \c qmldir, declare them in your \c CMakeLists.txt before the \l qt_add_qml_module call with: +\badcode +set_source_files_properties(MySingleton.qml PROPERTIES QT_QML_SINGLETON_TYPE TRUE) +\endcode + +Delete the handwritten \c qmldir after that. + +\section1 Remove qmltypes files generated by qmlplugindump + +\l qt_add_qml_module auto-generates \c qmltypes files when all your types are using +\l{Registering C++ Types with the QML Type System}{declarative type registration}, which removes +the need to generate \c qmltypes files by hand using tools like \c qmlplugindump. + +To achieve that, remove manual calls to \c qmlRegisterType and its variants. Then, +\l{Registering C++ Types with the QML Type System}{register your types declaratively} by using +\l QML_ELEMENT, for example: +\badcode +// add this header +#include <QtQml/qqmlregistrations.h> + +class MyComponent: public QObject { + Q_OBJECT + + // add this line to register MyComponent as 'MyComponent' in QML. + QML_ELEMENT + .... +}; +\endcode + +See \l{Registering C++ Types with the QML Type System} on how to handle more complicated +registration cases like foreign type registration. + +Delete the handwritten \c qmltypes files after that. + +\section1 Remove handwritten type registration plugins + +\l qt_add_qml_module can generate a \l {Creating C++ Plugins for QML}{QML module plugin} +automatically for you. You don't need a handwritten plugin if your plugin's only task is to do type +registration. Remove the plugin altogether if switching to declarative type registration did remove +all the code from your plugin. + +Make sure that you \e remove the \c NO_PLUGIN, \c NO_PLUGIN_OPTIONAL, \c +NO_CREATE_PLUGIN_TARGET, and \c NO_GENERATE_PLUGIN_SOURCE arguments from \l qt_add_qml_module to +allow automatic plugin generation. + +\section1 Remove qrc files + +\l qt_add_qml_module automatically generates \c qrc files. To list resources in the \c qrc files, +like images or sound files, add them to \l{qt_add_qml_module}'s \c RESOURCES argument. +You can find the Module's resources under \c{:/qt/qml/MyQmlLibraryModule/}. + +\section1 Replace directory imports with QML module imports + +Replace directory imports with QML module imports. For example, +\badcode +import "content" // contains SomeType.qml +// becomes +import MyQmlModule // contains SomeType.qml + +SomeType { + ... +} +\endcode + +Note that files inside a QML module automatically import their own QML module. You can remove the +self-imports. + +\sa {Changes to Qt QML}, {Modern QML modules} +*/ |
