Compilateur de types QML
Le compilateur de types QML, qmltc, est un outil fourni avec Qt pour traduire les types QML en types C++ qui sont compilés à l'avance dans le cadre du code utilisateur. L'utilisation de qmltc peut conduire à de meilleures performances d'exécution en raison du plus grand nombre d'opportunités d'optimisation disponibles pour le compilateur par rapport à une création d'objet basée sur QQmlComponent. Le qmltc fait partie de la chaîne d'outils du compilateurQt Quick .
De par sa conception, le qmltc produit un code orienté vers l'utilisateur. Ce code est censé être utilisé directement par l'application C++, sinon vous n'en tirerez aucun avantage. Ce code généré remplace essentiellement QQmlComponent et ses API pour créer des objets à partir de documents QML. Pour plus d'informations, voir Utilisation de qmltc dans une application QML et Notions de base sur les sorties générées.
Pour activer qmltc :
- Créez un module QML approprié pour votre application.
- Invoquer qmltc, par exemple, par l'intermédiaire de l'API CMake.
#includeAjouter le(s) fichier(s) d'en-tête généré(s) dans le code source de l'application.- Instancier un objet du type généré.
Dans ce flux de travail, qmltc s'exécute généralement pendant le processus de construction. Ainsi, lorsque qmltc rejette un document QML (que ce soit en raison d'erreurs ou d'avertissements, ou en raison de constructions que qmltc ne prend pas encore en charge), le processus de construction échoue. Ceci est similaire à la façon dont vous recevez des erreurs qmllint lorsque vous activez la génération automatique de cibles de linting pendant la création de modules QML et que vous essayez ensuite de les "construire" pour exécuter qmllint.
Attention : qmltc est actuellement en phase d'aperçu technique et peut ne pas compiler un programme QML arbitraire (voir Limitations connues pour plus de détails). Lorsque qmltc échoue, rien n'est généré car votre application ne peut pas raisonnablement utiliser la sortie de qmltc. Si votre programme contient des erreurs (ou des avertissements insolubles), elles doivent être corrigées pour permettre la compilation. La règle générale est d'adhérer aux meilleures pratiques et de suivre les conseils de qmllint.
Note : qmltc ne garantit pas que le C++ généré reste compatible avec l'API, la source ou le binaire entre les versions passées ou futures, même les versions correctives. De plus, les applications compilées par qmltc et utilisant les modules QML de Qt devront être liées à l'API privée de Qt. En effet, les modules Qt QML ne fournissent généralement pas d'API C++ publique, puisque leur utilisation principale se fait par le biais de QML.
Utilisation de qmltc dans une application QML
Du point de vue du système de construction, l'ajout de la compilation qmltc n'est pas très différent de l'ajout de la génération de cache qml. Naïvement, le processus de compilation pourrait être décrit comme suit :

Bien que le processus de compilation réel soit beaucoup plus délicat, ce diagramme capture les composants principaux que qmltc utilise : les fichiers QML eux-mêmes et qmldir avec les informations qmltypes. Les applications les plus simples ont généralement un qmldir plutôt primitif, mais en général, qmldir peut être complexe, fournissant des informations de type essentielles et bien emballées sur lesquelles qmltc s'appuie pour effectuer une traduction correcte de QML en C++.
Néanmoins, l'ajout d'une étape de compilation supplémentaire n'est pas suffisant dans le cas de qmltc. Le code de l'application doit également être modifié pour utiliser les classes générées par qmltc au lieu de QQmlComponent ou de ses alternatives de plus haut niveau.
Compilation du code QML avec qmltc
Qt, à partir de Qt 6, utilise CMake pour construire ses différents composants. Les projets des utilisateurs peuvent - et sont encouragés à - utiliser CMake pour construire leurs composants en utilisant Qt. L'ajout d'un support de compilation qmltc prêt à l'emploi à votre projet nécessiterait également un flux de construction piloté par CMake, puisque ce flux est centré sur les modules QML appropriés et leur infrastructure.
La manière la plus simple d'ajouter la compilation qmltc est d'utiliser l'API CMake dédiée dans le cadre de la création d'un module QML pour l'application. Considérons une structure de répertoire d'application simple :
. ├── CMakeLists.txt ├── myspecialtype.h // C++ type exposed to QML ├── myspecialtype.cpp ├── myApp.qml // main QML page ├── MyButton.qml // custom UI button ├── MySlider.qml // custom UI slider └── main.cpp // main C++ application file
Le code CMake ressemblerait alors à ce qui suit :
# Use "my_qmltc_example" as an application name:
set(application_name my_qmltc_example)
# Create a CMake target, add C++ source files, link libraries, etc...
# Specify a list of QML files to be compiled:
set(application_qml_files
myApp.qml
MyButton.qml
MySlider.qml
)
# Make the application into a proper QML module:
qt6_add_qml_module(${application_name}
URI QmltcExample
QML_FILES ${application_qml_files}
# Compile qml files (listed in QML_FILES) to C++ using qmltc and add these
# files to the application binary:
ENABLE_TYPE_COMPILER
NO_GENERATE_EXTRA_QMLDIRS
)
# (qmltc-specific) Link *private* libraries that correspond to QML modules:
find_package(Qt6 COMPONENTS QmlPrivate QuickPrivate)
target_link_libraries(${application_name} PRIVATE Qt::QmlPrivate Qt::QuickPrivate)Utilisation du code C++ généré
Contrairement à l'instanciation de QQmlComponent, le résultat de qmltc, qui est du code C++, est utilisé directement par l'application. En règle générale, la construction d'un nouvel objet en C++ équivaut à la création d'un nouvel objet par le biais de QQmlComponent::create(). Une fois créé, l'objet peut être manipulé à partir de C++ ou, par exemple, combiné avec QQuickWindow pour être dessiné à l'écran.
Si un type compilé expose certaines propriétés requises, `qmltc` demandera une valeur initiale pour ces propriétés dans le constructeur de l'objet généré.
De plus, le constructeur d'un objet qmltc peut être fourni avec un callback pour définir les valeurs initiales des propriétés du composant.
Avec un fichier myApp.qml, le code de l'application (dans les deux cas) ressemblerait typiquement à ceci :
#include <QtQml/qqmlcomponent.h> QGuiApplication app(argc, argv); app.setApplicationDisplayName(QStringLiteral("This example is powered by QQmlComponent :(")); QQmlEngine e; // If the root element is Window, you don't need to create a Window. // The snippet is for the cases where the root element is not a Window. QQuickWindow window; QQmlComponent component(&e); component.loadUrl( QUrl(QStringLiteral("qrc:/qt/qml/QmltcExample/myApp.qml"))); QScopedPointer<QObject> documentRoot(component.create()); QQuickItem *documentRootItem = qobject_cast<QQuickItem *>(documentRoot.get()); documentRootItem->setParentItem(window.contentItem()); window.setHeight(documentRootItem->height()); window.setWidth(documentRootItem->width()); // ... window.show(); app.exec();
#include "myapp.h" // include generated C++ header QGuiApplication app(argc, argv); app.setApplicationDisplayName(QStringLiteral("This example is powered by qmltc!")); QQmlEngine e; // If the root element is Window, you don't need to create a Window. // The snippet is for the cases where the root element is not a Window. QQuickWindow window; QScopedPointer<QmltcExample::myApp> documentRoot( new QmltcExample::myApp(&e, nullptr, [](auto& component){ component.setWidth(800); })); documentRoot->setParentItem(window.contentItem()); window.setHeight(documentRoot->height()); window.setWidth(documentRoot->width()); // ... window.show(); app.exec();
Moteur QML
Le code généré utilise QQmlEngine pour interagir avec les parties dynamiques d'un document QML - principalement le code JavaScript. Pour que cela fonctionne, aucune disposition particulière n'est nécessaire. Toute instance de QQmlEngine passée au constructeur d'un objet de classe généré par qmltc devrait fonctionner correctement, tout comme QQmlComponent(engine). Cela signifie également que vous pouvez utiliser QQmlEngine methods qui affecte le comportement de QML. Cependant, il y a des mises en garde. Contrairement à la création d'objets basée sur QQmlComponent, qmltc lui-même ne s'appuie pas sur QQmlEngine lors de la compilation du code en C++. Par exemple, QQmlEngine::addImportPath("/foo/bar/") - qui se traduit normalement par un chemin d'importation supplémentaire à rechercher - serait complètement ignoré par la procédure qmltc anticipée.
Note : Pour ajouter des chemins d'importation à la compilation qmltc, envisagez d'utiliser un argument pertinent de la commande CMake à la place.
En règle générale, vous pouvez envisager les choses de la manière suivante : QQmlEngine implique l'exécution du processus d'application, alors que qmltc ne le fait pas puisqu'il opère avant même que votre application ne soit compilée. Puisque qmltc n'essaie pas d'inspecter le code source C++ de votre application, il n'a aucun moyen de connaître certains types de manipulations QML que vous, en tant qu'utilisateur, effectuez. Au lieu d'utiliser QQmlEngine et les routines d'exécution correspondantes pour exposer les types à QML, en ajoutant des chemins d'importation, etc., vous êtes pratiquement obligé de créer des modules QML qui se comportent bien et d'utiliser l'enregistrement déclaratif des types QML.
Attention : Bien que qmltc travaille en étroite collaboration avec QQmlEngine et crée du code C++, les classes générées ne peuvent pas être exposées à QML et utilisées par l'intermédiaire de QQmlComponent.
Principes de base des sorties générées
qmltc qmltc vise à être compatible avec le modèle d'exécution QML existant. Cela implique que le code généré est à peu près équivalent à la logique de configuration interne de QQmlComponent et que vous devriez donc être en mesure de comprendre le comportement, la sémantique et l'API de votre type QML de la même manière que vous le faites actuellement - en inspectant visuellement le document QML correspondant.
Cependant, le code généré est encore quelque peu déroutant, surtout si l'on considère que votre application devrait utiliser directement la sortie qmltc du côté C++. Il y a deux parties dans le code généré : La structure des fichiers de compilation CMake et le format C++ généré. La première est couverte par l'API CMake de qmltc et la seconde est couverte ici.
Considérons un type HelloWorld simple, qui possède une propriété hello, une fonction pour imprimer cette propriété et un signal émis lorsque l'objet de ce type est créé :
// HelloWorld.qml import QtQml QtObject { id: me property string hello: "Hello, qmltc!" function printHello(prefix: string, suffix: string) { console.log(prefix + me.hello + suffix); } signal created() Component.onCompleted: me.created(); }
En fournissant une alternative C++ de ce type Qt XML, la classe C++ aurait besoin d'une macro de système méta-objet spécifique à QML, d'une décoration Q_PROPERTY pour la propriété hello, d'une fonction d'impression C++ Q_INVOKABLE et d'une définition de signal Qt normale. De même, qmltc traduirait le type HelloWorld donné en gros ce qui suit :
class HelloWorld : public QObject { Q_OBJECT QML_ELEMENT Q_PROPERTY(QString hello READ hello WRITE setHello BINDABLE bindableHello) public: HelloWorld(QQmlEngine* engine, QObject* parent = nullptr, [[maybe_unused]] qxp::function_ref<void(PropertyInitializer&)> initializer = [](PropertyInitializer&){}); Q_SIGNALS: void created(); public: QString hello(); void setHello(const QString& hello_); QBindable<QString> bindableHello(); Q_INVOKABLE void printHello(passByConstRefOrValue<QString> prefix, passByConstRefOrValue<QString> suffix); // ... };
Même si les détails spécifiques du type généré peuvent différer, les aspects universels demeurent. Par exemple :
- Les types QML dans un document sont traduits en types C++, en fonction des informations visibles par le compilateur.
- Les propriétés sont traduites en propriétés C++ avec les déclarations Q_PROPERTY.
- Les fonctions JavaScript deviennent des fonctions
Q_INVOKABLEC++. - Les signaux QML sont transformés en signaux C++ Qt.
- Les énumérations QML sont converties en énumérations C++ avec des déclarations
Q_ENUM.
Un autre détail est la façon dont qmltc génère les noms de classe. Un nom de classe pour un type QML donné est automatiquement déduit du document QML définissant ce type : le nom de fichier QML sans extension (jusqu'au premier ., également connu sous le nom de base) devient un nom de classe. La casse du nom de fichier est préservée. Ainsi, HelloWorld.qml donnerait class HelloWorld et helloWoRlD.qml class helloWoRlD . Conformément à la convention QML, si le nom de fichier d'un document QML commence par une lettre minuscule, la classe C++ générée est supposée être anonyme et marquée par QML_ANONYMOUS.
Pour l'instant, bien que le code généré soit prêt à être utilisé du côté de l'application C++, vous devriez généralement limiter les appels aux API générées. Préférez plutôt mettre en œuvre la logique de l'application en QML/JavaScript et écrire à la main les types C++ exposés à QML, en utilisant les classes créées par qmltc pour l'instanciation simple d'objets. Bien que le C++ généré vous donne un accès direct (et généralement plus rapide) aux éléments du type définis par QML, la compréhension d'un tel code peut s'avérer difficile.
Limites connues
Bien qu'il couvre de nombreuses fonctionnalités QML courantes, qmltc n'en est encore qu'au début de son développement et certains éléments ne sont pas encore pris en charge.
Les modules QML importés qui consistent en des types définis par QML (tels que QtQuick.Controls) peuvent ne pas être compilés correctement, même si ces types définis par QML ont été compilés par qmltc.... Actuellement, vous pouvez utiliser de manière fiable les modules QtQml et QtQuick ainsi que tout autre module QML qui ne contient que des classes C++ exposées à QML.
En outre, il y a des particularités plus fondamentales à prendre en compte :
- Les modules Qt QML s'appuient généralement sur des bibliothèques C++ pour faire le gros du travail. Souvent, ces bibliothèques ne fournissent pas d'API C++ publique (puisque leur utilisation principale se fait par le biais de QML). Pour les utilisateurs de qmltc, cela signifie que leurs applications doivent être liées à des bibliothèques Qt privées.
- En raison de la nature de la génération de code de qmltc, les plugins QML sont inutilisables à des fins de compilation. Au lieu de cela, les modules QML - qui utilisent un plugin - doivent s'assurer que les données du plugin sont accessibles au moment de la compilation. Ces modules QML auraient alors des plugins optionnels. Dans la plupart des cas, les informations au moment de la compilation peuvent être fournies par un fichier d'en-tête (avec des déclarations C++) et une bibliothèque liante (avec des définitions C++). Le code utilisateur est responsable (généralement par l'intermédiaire de CMake) de l'inclusion d'un chemin vers le fichier d'en-tête et de l'établissement de liens avec la bibliothèque de modules QML.
Note : Etant donné le statut de tech preview du compilateur, il est possible que vous rencontriez des bogues dans qmltc, dans le code généré, ou dans d'autres parties liées. Nous vous encourageons à soumettre un rapport de bogue dans ce cas.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.