Interaction avec des objets QML depuis le C++
Tous les types d'objets QML sont des types dérivés d'QObject, qu'ils soient implémentés en interne par le moteur ou définis par des sources tierces. Cela signifie que le moteur QML peut utiliser le système de méta-objets Qt pour instancier dynamiquement n'importe quel type d'objet QML et inspecter les objets créés.
Cette fonctionnalité est utile pour créer des objets QML à partir de code C++, que ce soit pour afficher un objet QML pouvant être rendu visuellement ou pour intégrer les données d'un objet QML non visuel dans une application C++. Une fois qu'un objet QML est créé, il peut être inspecté depuis le C++ afin de lire et d'écrire dans ses propriétés, d'appeler des méthodes et de recevoir des notifications de signaux.
Pour plus d’informations sur le C++ et les différentes méthodes d’intégration QML, consultez la page de présentation de l’intégration C++ et QML.
Chargement d'objets QML depuis le C++
Un document QML peut être chargé à l'aide de ` QQmlComponent ` ou ` QQuickView`. ` QQmlComponent ` charge un document QML sous la forme d'un objet C++ qui peut ensuite être modifié à partir du code C++. ` QQuickView ` effectue également cette opération, mais comme ` QQuickView ` est une classe dérivée de ` QWindow`, l'objet chargé sera également affiché à l'écran ; ` QQuickView ` est généralement utilisé pour intégrer un objet QML affichable dans l'interface utilisateur d'une application.
Par exemple, supposons qu’il existe un fichier MyItem.qml qui se présente comme suit :
import QtQuick
Item {
width: 100; height: 100
}Ce document QML peut être chargé à l’aide de ` QQmlComponent ` ou ` QQuickView ` avec le code C++ suivant. L’utilisation d’un ` QQmlComponent ` nécessite d’appeler ` QQmlComponent::create()` pour créer une nouvelle instance du composant, tandis qu’un ` QQuickView ` crée automatiquement une instance du composant, accessible via ` QQuickView::rootObject()` :
| |
Cette variable ` object ` correspond à l'instance du composant ` MyItem.qml ` qui a été créée. Vous pouvez désormais modifier les propriétés de l'élément à l'aide de ` QObject::setProperty()` ou ` QQmlProperty::write()` :
object->setProperty("width", 500);
QQmlProperty(object, "width").write(500);La différence entre QObject::setProperty() et QQmlProperty::write() réside dans le fait que cette dernière opération supprime également la liaison en plus de définir la valeur de la propriété. Par exemple, supposons que l’affectation width ci-dessus ait constitué une liaison vers height:
width: heightSi la valeur de ` height ` de ` Item ` venait à changer après l’appel de ` object->setProperty("width", 500) `, ` width ` serait à nouveau mis à jour, car la liaison reste active. En revanche, si la valeur de ` height ` venait à changer après l’appel de ` QQmlProperty(object, "width").write(500) `, ` width ` ne serait pas modifié, car la liaison n’existe plus.
Vous pouvez également convertir l'objet en son type réel et appeler des méthodes en toute sécurité à la compilation. Dans ce cas, l'objet de base de ` MyItem.qml ` est un ` Item`, qui est défini par la classe ` QQuickItem ` :
QQuickItem *item = qobject_cast<QQuickItem*>(object);
item->setWidth(500);Vous pouvez également vous connecter à n’importe quel signal ou appeler des méthodes définies dans le composant à l’aide de ` QMetaObject::invokeMethod()` et ` QObject::connect()`. Reportez-vous aux sections « Appel de méthodes QML » et « Connexion à des signaux QML » ci-dessous pour plus de détails.
Accès aux objets QML via des interfaces C++ bien définies
La meilleure façon d’interagir avec QML depuis le C++ consiste à définir une interface à cet effet en C++ et à y accéder directement depuis QML. Avec d’autres méthodes, la refactorisation de votre code QML peut facilement entraîner une rupture de l’interaction entre QML et C++. Cela facilite également la compréhension de l’interaction entre le code QML et C++, car le fait qu’elle soit pilotée via QML permet une analyse plus aisée tant par les utilisateurs que par des outils tels que qmllint. Accéder à QML depuis le C++ conduit à un code QML qui ne peut être compris sans vérifier manuellement qu’aucun code C++ externe ne modifie un composant QML donné ; même dans ce cas, l’étendue de l’accès peut évoluer au fil du temps, ce qui rend l’utilisation continue de cette stratégie fastidieuse en termes de maintenance.
Pour laisser le QML piloter l’interaction, vous devez d’abord définir une interface C++ :
class CppInterface : public QObject
{
Q_OBJECT
QML_ELEMENT
// ...
};Avec une approche pilotée par QML, cette interface peut être utilisée de deux manières :
Singletons
Une option consiste à enregistrer l'interface en tant que singleton en ajoutant la macro QML_SINGLETON à l'interface, ce qui la rend accessible à tous les composants. L'interface devient alors disponible via une simple instruction d'importation :
import my.company.module
Item {
Component.onCompleted: {
CppInterface.foo();
}
}Utilisez cette approche si vous avez besoin de votre interface à d'autres endroits que le composant racine, car le simple fait de transmettre un objet nécessiterait de le transmettre explicitement à d'autres composants via une propriété ou d'utiliser la méthode lente et déconseillée de l'accès non qualifié.
Propriétés initiales
Une autre option consiste à marquer l’interface comme non créable via ` QML_UNCREATABLE ` et à la fournir au composant QML racine en utilisant ` QQmlComponent::createWithInitialProperties()` et une propriété obligatoire côté QML.
Votre composant racine pourrait ressembler à ceci :
import QtQuick
Item {
required property CppInterface interface
Component.onCompleted: {
interface.foo();
}
}Le fait de marquer la propriété comme obligatoire ici empêche le composant d'être créé sans que la propriété d'interface ne soit définie.
Vous pouvez ensuite initialiser votre composant de la même manière que celle décrite dans la section « Chargement d’objets QML depuis C++ », mais en utilisant ` createWithInitialProperties()` :
component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});Cette méthode est à privilégier si vous savez que votre interface ne doit être accessible qu’au composant racine. Elle permet également de se connecter plus facilement aux signaux et slots de l’interface côté C++.
Si aucune de ces méthodes ne répond à vos besoins, vous pouvez envisager d’utiliser plutôt les modèles C++.
Accès aux objets QML chargés par nom d'objet
Les composants QML sont essentiellement des arborescences d’objets dont les enfants possèdent à leur tour des frères et leurs propres enfants. Les objets enfants des composants QML peuvent être localisés à l’aide de la propriété ` QObject::objectName ` avec la méthode ` QObject::findChild()`. Par exemple, si l’élément racine de ` MyItem.qml ` avait un enfant de type ` Rectangle ` :
import QtQuick
Item {
width: 100; height: 100
Rectangle {
anchors.fill: parent
objectName: "rect"
}
}L'élément enfant pourrait être localisé comme suit :
Notez qu’un objet peut avoir plusieurs enfants ayant la même « objectName ». Par exemple, la méthode ` ListView ` crée plusieurs instances de son délégué ; ainsi, si ce délégué est déclaré avec un «objectName» particulier, la « ListView » comportera plusieurs enfants ayant la même « objectName ». Dans ce cas, la méthode ` QObject::findChildren()` peut être utilisée pour trouver tous les enfants dont la « objectName » correspond.
Avertissement : bien qu’ il soit possible d’accéder à des objets QML depuis C++ et de les manipuler, cette approche n’est pas recommandée, sauf à des fins de test et de prototypage. L’un des atouts de l’intégration entre QML et C++ réside dans la possibilité d’implémenter des interfaces utilisateur en QML indépendamment de la logique C++ et du backend de données, et cela ne fonctionne plus si le côté C++ commence à manipuler directement le QML. Une telle approche rend également difficile la modification de l’interface utilisateur QML sans affecter son équivalent C++.
Accès aux membres d’un type d’objet QML depuis le C++
Propriétés
Toutes les propriétés déclarées dans un objet QML sont automatiquement accessibles depuis le C++. Prenons un élément QML tel que celui-ci :
La valeur de la propriété ` someNumber ` peut être définie et lue à l'aide de ` QQmlProperty`, ou de ` QObject::setProperty()` et ` QObject::property()` :
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject*object = component.create();
qDebug() << "Property value:" << QQmlProperty::read(object, "someNumber").toInt();
QQmlProperty::write(object, "someNumber", 5000) ;
qDebug() << "Property value:" << object->property("someNumber").toInt();
object->setProperty("someNumber", 100);Vous devez toujours utiliser QObject::setProperty(), QQmlProperty ou QMetaProperty::write() pour modifier la valeur d’une propriété QML, afin de vous assurer que le moteur QML soit informé de la modification de la propriété. Par exemple, supposons que vous ayez un type personnalisé PushButton avec une propriété buttonText qui reflète en interne la valeur d’une variable membre m_buttonText. Modifier directement la variable membre comme ceci n’est pas une bonne idée :
//bad code
QQmlComponent component(engine, "MyButton.qml");
PushButton *button = qobject_cast<PushButton*>(component.create());
button->m_buttonText = "Click me";Comme la valeur est modifiée directement, cela contourne le système de méta-objets de Qt et le moteur QML n’est pas informé de la modification de la propriété. Cela signifie que les liaisons de propriété vers buttonText ne seraient pas mises à jour, et qu’aucun gestionnaire onButtonTextChanged ne serait appelé.
Appel de méthodes QML
Toutes les méthodes QML sont exposées au système de méta-objets et peuvent être appelées depuis le C++ à l’aide de ` QMetaObject::invokeMethod()`. Vous pouvez spécifier les types des paramètres et de la valeur de retour après le caractère « : », comme le montre l’extrait de code ci-dessous. Cela peut s’avérer utile, par exemple, lorsque vous souhaitez connecter un signal en C++ présentant une signature donnée à une méthode définie en QML. Si vous omettez les types, la signature C++ utilisera ` QVariant`.
Voici une application C++ qui appelle une méthode QML à l'aide de ` QMetaObject::invokeMethod()` :
| QML | |
| C++ | |
Notez le type du paramètre et le type de retour spécifiés après les deux-points. Vous pouvez utiliser des types de valeur et des types d'objet comme noms de type.
Si le type est omis ou spécifié sous la forme « var » en QML, vous devez alors passer « QVariant » comme type avec « Q_RETURN_ARG() » et « Q_ARG() » lors de l’appel de « QMetaObject::invokeMethod ».
Connexion aux signaux QML
Tous les signaux QML sont automatiquement accessibles en C++ et peuvent être connectés à l’aide de ` QObject::connect()` comme n’importe quel signal Qt C++ ordinaire. En contrepartie, tout signal C++ peut être reçu par un objet QML à l’aide de gestionnaires de signaux.
Voici un composant QML doté d’un signal nommé qmlSignal, qui est émis avec un paramètre de type chaîne de caractères. Ce signal est connecté au slot d’un objet C++ à l’aide de QObject::connect(), de sorte que la méthode cppSlot() soit appelée chaque fois que le signal qmlSignal est émis :
|
Un type d’objet QML dans un paramètre de signal est converti en un pointeur vers la classe en C++ :
|
© 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.