Utiliser QML dans les applications C++QML est conçu pour être facilement extensible depuis et vers C++. Les classes dans le module Qt Declarative permettent de charger et d'utiliser les composants QML à partir du C++ et, à travers le système de métaobjets, les objets QML et C++ peuvent facilement communiquer grâce aux signaux et slots de Qt. De plus, des plug-ins QML peuvent être écrits pour créer des composants QML réutilisables. Vous pouvez souhaiter mélanger le QML et le C++ pour de nombreuses raisons, par exemple :
Pour utiliser le module Qt Declarative, vous devez inclure et lier le module approprié, comme montré dans la page d'index du module. La documentation de l'environnement d'exécution de Qt Declarative présente la façon de construire une application C++ basique utilisant ce module. Classes principales du moduleLe module Qt Declarative fournit un ensemble de fonctions C++ pour étendre vos applications QML à partir du C++ et pour inclure du QML dans les applications C++. Le module Qt Declarative possède plusieurs classes maîtresses pour ce faire.
Un QDeclarativeEngine permet la configuration des paramètres globaux appliqués à tous ses composants QML : par exemple, le QNetworkAccessManager à utiliser pour les communications réseau ou encore le chemin à utiliser pour la sauvegarde persistante. Le QDeclarativeComponent est utilisé pour charger les documents QML. Chaque QDeclarativeComponent représente un seul document. Un composant peut être créé à partir d'une URL ou d'un chemin sur un document QML ou encore à partir du code QML brut du document. Les instances des composants sont instanciées à travers la méthode QDeclarativeComponent::create(), comme suit : QDeclarativeEngine engine; QDeclarativeComponent component(&engine, QUrl::fromLocalFile("MyRectangle.qml")); QObject *rectangleInstance = component.create(); // ... delete rectangleInstance; Les documents QML peuvent aussi être chargés en utilisant QDeclarativeView. Cette classe fournit une vue basée sur QWidget pour intégrer le composant QML dans les applications basées sur QGraphicsView (pour les autres méthodes d'intégration de QML dans les applications basées sur un QWidget, voir intégration du QML avec un code d'interface utilisateur existant). Approches pour utiliser QML avec C++Il y a plusieurs façons d'étendre les applications QML avec C++. Par exemple, vous pouvez :
Ces méthodes sont présentées ci-dessous. Naturellement, ces approches ne sont pas exclusives et vous pouvez les combiner dans vos applications comme bon vous semble. Chargement des composants QML à partir de C++Un document QML peut être chargé avec QDeclarativeComponent ou QDeclarativeView. QDeclarativeComponent charge un composant QML sous forme d'un objet C++ ; QDeclarativeView le fait aussi mais charge le composant directement dans un QGraphicsView, ce qui est pratique pour charger un composant QML affichable dans une application basée sur QWidget. Par exemple, supposez qu'il existe un fichier MyItem.qml contenant : import QtQuick 1.0 Item { width: 100; height: 100 } Ce document QML peut être chargé avec QDeclarativeComponent ou QDeclarativeView avec le code C++ suivant. L'utilisation d'un QDeclarativeComponent nécessite l'appel à la fonction QDeclarativeComponent::create() pour créer une nouvelle instance du composant, alors qu'un QDeclarativeView crée automatiquement une instance du composant, accessible par la fonction QDeclarativeView::rootObject() :
Cet objet object est une instance du composant MyItem.qml qui a été créé. Vous pouvez maintenant modifier les propriétés de l'élément avec la fonction QObject::setProperty() ou QDeclarativeProperty : object->setProperty("width", 500); QDeclarativeProperty(object, "width").write(500); Alternativement, vous pouvez transtyper l'objet vers son type réel et appeler des fonctions avec un contrôle de validité à la compilation. Dans ce cas, l'objet de base du MyItem.qml est un Item, qui est défini par la classe QDeclarativeItem : QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(object); item->setWidth(500); Vous pouvez aussi connecter n'importe quels signaux ou appels de fonctions définis dans le composant avec les fonctions QMetaObject::invokeMethod() et QObject::connect(). Voir Échanges de données entre QML et C++ ci-dessous pour plus de détails. Trouver les objets enfants Les composants QML sont essentiellement des arbres d'objets avec enfants qui ont des semblables ayant leurs propres enfants. Les objets enfants des composants QML peuvent être trouvés en utilisant la propriété QObject::objectName avec la fonction QObject::findChild(). Par exemple, si l'élément racine du fichier MyItem.qml possède un élément Rectangle enfant : import QtQuick 1.0 Item { width: 100; height: 100 Rectangle { anchors.fill: parent objectName: "rect" } } Cet enfant peut être trouvé avec le code suivant : QObject *rect = object->findChild<QObject*>("rect"); if (rect) rect->setProperty("color", "red"); Si le nom d'objet objectName est utilisé à l'intérieur d'un délégué d'une ListView, Repeater ou d'un autre élément qui crée plusieurs instances de ses délégués, plusieurs enfants ayant le nom d'objet objectName seront trouvés. Dans ce cas, la fonction QObject::findChildren() peut être utilisée pour trouver tous les enfants correspondant au nom d'objet objectName. Attention : même s'il est possible d'utiliser C++ pour accéder et manipuler les objets QML profondément dans l'arbre d'objets, nous recommandons de n'utiliser cette méthode que lors des prototypages et tests. Une force de l'intégration de QML et de C++ est la possibilité d'implémenter l'interface utilisateur QML séparément de la logique du C++ et des ensembles de données et cette particularité est perdue si le C++ s'enfonce profondément dans les composants QML afin de les contrôler directement. Par exemple, cela rendrait difficile de remplacer un composant QML par un autre, si le nouveau composant ne possède pas les noms d'objets requis. Il est préférable pour l'implémentation C++ de connaitre le moins possible l'implémentation de l'interface utilisateur QML et la composition des arbres d'objets QML. Intégration des objets C++ dans les composants QMLLors du chargement d'une scène QML dans une application C++, il peut être utile de directement intégrer les données C++ dans l'objet QML. QDeclarativeContext permet cela en exposant les données au contexte du composant QML, rendant possible l'injection des données du C++ dans le QML. Par exemple, voici un élément QML qui se réfère à une date courante currentDateTime qui n'est pas dans la portée courante : // MyItem.qml import QtQuick 1.0 Text { text: currentDateTime } Cette date courante currentDateTime peut être définie directement par l'application C++ qui charge le composant QML, grâce à la fonction QDeclarativeContext::setContextProperty() : QDeclarativeView view; view.rootContext()->setContextProperty("currentDateTime", QDateTime::currentDateTime()); view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); Les propriétés de contexte peuvent contenir soit des QVariant soit des QObject*. Cela signifie que les objets C++ personnalisés peuvent aussi être injectés en utilisant cette approche et que ces objets peuvent être modifiés et lus directement dans le QML. Ici, nous modifions l'exemple ci-dessus pour intégrer une instance de QObject à la place du QDateTime et le QML utilise une méthode de cette instance :
Notez que les valeurs de date/temps retournées par C++ au QML peuvent être formatées avec les fonctions Qt.formatDateTime() et les fonctions associées. Si l'élément QML doit recevoir des signaux à partir d'une propriété de contexte, il peut être connecté en utilisant l'élément Connections. Par exemple, si ApplicationData possède un signal dataChanged(), ce signal peut être connecté en utilisant un gestionnaire onDataChanged dans un objet Connections : Text { text: applicationData.getCurrentDateTime() Connections { target: applicationData onDataChanged: console.log("The application data changed!") } } Les propriétés de contexte peuvent être utiles pour utiliser des modèles de données C++ dans une vue QML. Voir le ListModel de chaînes de caractères, le ListModel d'objets et les modèles AbstractItemModel pour respectivement des exemples d'utilisation de QStringListModel, des modèles basés sur QObjectList et de QAbstractItemModel dans les vues QML. Voir aussi la documentation de QDeclarativeContext pour plus d'informations. Définir de nouveaux éléments QMLBien que les nouveaux éléments QML puissent être définis en QML, ils peuvent aussi être définis par des classes C++ ; en fait, la plupart des éléments QML principaux sont implémentés à travers des classes C++. Lorsque vous créez un objet QML en utilisant l'un de ces éléments, vous effectuez simplement la création d'une instance d'une classe C++ basée sur QObject et la définition de ses propriétés. Par exemple, pour une classe ImageViewer avec une propriété URL image : #include <QtCore> #include <QtDeclarative> class ImageViewer : public QDeclarativeItem { Q_OBJECT Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged) public: void setImage(const QUrl &url); QUrl image() const; signals: void imageChanged(); }; À part le fait qu'elle hérite de QDeclarativeItem, c'est une classe ordinaire qui peut exister en dehors du QML. Une fois qu'elle est enregistrée dans le moteur QML avec qmlRegisterType() : qmlRegisterType<ImageViewer>("MyLibrary", 1, 0, "ImageViewer"); Tout code QML chargé par votre application C++ ou plug-in peut alors créer et manipuler les objets ImageViewer : import MyLibrary 1.0 ImageViewer { image: "smile.png" } Notez que les types C++ personnalisés n'ont pas à hériter de QDeclarativeItem ; cela n'est nécessaire que pour les objets affichables. Si l'élément n'est pas affichable, il peut simplement hériter de QObject. Pour plus d'informations sur la définition de nouveaux éléments QML, voir la page sur l'écriture d'extensions QML avec le C++ et la documentation étendre le QML avec C++. Échanger des données entre QML et C++Les objets QML et C++ peuvent communiquer les uns avec les autres avec des signaux, slots et des modifications de propriétés. Pour un objet C++, les données exposées au système de métaobjets de Qt - c'est-à-dire les propriétés, signaux, slots et les méthodes Q_INVOKABLE - sont disponibles pour QML. Du côté de QML, toutes les données des objets QML sont automatiquement disponibles dans le système de méta-objets et peuvent être utilisées à partir du C++. Appel de fonctionsLes fonctions QML peuvent être appelées à partir du C++ et vice versa. Toutes les fonctions QML sont exposées au système de métaobjets et peuvent être appelées avec la fonction QMetaObject::invokeMethod(). Voici une application C++ qui appelle une fonction QML :
Remarquez que les arguments Q_RETURN_ARG() et Q_ARG() de la fonction QMetaObject::invokeMethod() doivent être spécifiés comme types QVariant, car c'est le type de donnée générique utilisé par les fonctions QML. Pour appeler une fonction C++ à partir du code QML, la fonction doit être soit un slot Qt, soit être marquée avec la macro Q_INVOKABLE, pour être disponible en QML. Dans l'exemple suivant, le code QML appelle des méthodes sur l'objet myObject, qui a été défini avec la fonction QDeclarativeContext::setContextProperty() :
QML gère l'appel des fonctions C++ surchargées. S'il existe plusieurs fonctions C++ possédant le même nom mais avec différents arguments, la fonction appropriée sera appelée selon le nombre et les types des arguments fournis. Recevoir des signauxTous les signaux QML sont automatiquement utilisables en C++ et peuvent être connectés en utilisant la fonction QObject::connect() comme avec tout signal C++ ordinaire. Inversement, n'importe quel signal C++ peut être reçu par un objet QML en utilisant un gestionnaire de signal. Voici un composant QML avec un signal nommé qmlSignal. Ce signal est connecté à un slot C++ avec QObject::connect(), afin que la méthode cppSlot() soit appelée à chaque fois que le signal qmlSignal est appelé :
Pour connecter un signal C++ à partir de QML, utilisez le gestionnaire de signal avec la syntaxe on<NomDuSignal>. Si l'objet C++ est directement constructible à partir du QML (voir Définir de nouveaux éléments QML ci-dessus) alors le gestionnaire de signal peut être défini à l'intérieur de la déclaration de l'objet. Dans l'exemple suivant, le code QML crée un objet ImageViewer et les signaux imageChanged et loadingError C++ de l'objet sont connectés en QML à travers les gestionnaires de signaux onImagedChanged et onLoadingError :
Notez que si un signal a été déclaré comme signal NOTIFY pour une propriété, cela permet à QML de recevoir le signal avec un gestionnaire on<Propriété>Changed même si le nom du signal ne suit pas la convention de nommage <Propriété>Changed. Dans l'exemple ci-dessus, si le signal « imageChanged » avait été nommé « imageModified », le gestionnaire de signal onImageChanged serait également appelé. Si l'objet avec le signal n'est pas créé dans le code QML et que l'élément QML ne possède qu'une référence sur l'objet créé ? par exemple, si l'objet a été défini avec la fonction QDeclarativeContext::setContextProperty() ? alors l'élément Connections peut être utilisé à la place pour créer le gestionnaire de signal :
Modifier les propriétésN'importe quelle propriété déclarée dans un objet QML est automatiquement accessible à partir du C++. Soit l'élément QML suivant : // MyItem.qml import QtQuick 1.0 Item { property int someNumber: 100 } La valeur de la propriété someNumber peut être définie et lue en utilisant QDeclarativeProperty ou QObject::setProperty() et QObject::property() : QDeclarativeEngine engine; QDeclarativeComponent component(&engine, "MyItem.qml"); QObject *object = component.create(); qDebug() << "Property value:" << QDeclarativeProperty::read(object, "someNumber").toInt(); QDeclarativeProperty::write(object, "someNumber", 5000); qDebug() << "Property value:" << object->property("someNumber").toInt(); object->setProperty("someNumber", 100); Vous devez toujours utiliser QObject::setProperty(), QDeclarativeProperty ou QMetaProperty::write() pour changer une valeur de propriété QML, afin d'être certain que le moteur QML a connaissance de ce changement. Par exemple, supposons que vous ayez un élément personnalisé PushButton avec une propriété buttonText qui reflète la valeur de la variable membre m_buttonText. Modifier cette variable directement n'est pas une bonne idée : // MAUVAIS! QDeclarativeComponent component(engine, "MyButton.qml"); PushButton *button = qobject_cast<PushButton*>(component.create()); button->m_buttonText = "Click me"; Parce que la valeur est modifiée directement, cela contourne le système de métaobjets de Qt et le moteur QML n'a pas connaissance du changement de la propriété. Cela signifie que le lien à buttonText ne sera pas mis à jour et qu'aucun gestionnaire onButtonTextChanged ne sera appelé. Toutes les propriétés Qt ? c'est-à-dire celles déclarées avec la macro Q_PROPERTY() ? sont accessibles à partir du QML. Voici une version modifiée d'un exemple précédent ; ici, la classe ApplicationData a une propriété backgroundColor . Cette propriété peut être écrite et lue à partir de QML :
Remarquez que le signal backgroundColorChanged est déclaré comme signal NOTIFY pour la propriété backgroundColor. Si une propriété Qt ne possède pas de signal NOTIFY associé, la propriété ne peut être utilisée pour la liaison de propriétés en QML, car le moteur QML ne serait pas notifié des changements de valeurs. Si vous utilisez des types personnalisés dans QML, assurez-vous de ce que leurs propriétés possèdent des signaux NOTIFY afin qu'ils puissent être utilisés dans la liaison de propriétés. Voir le Tutoriel : écrire des extensions QML avec C++ pour plus de détails et d'exemples sur l'utilisation des propriétés Qt dans QML. Types de données gérésToutes les données C++ utilisées en QML - qu'il s'agisse de propriétés ou de paramètres pour les signaux et fonctions - doivent être d'un type reconnaissable par QML. Par défaut, QML reconnait les types de données suivants :
|
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt 4.7 | |
Copyright © 2024 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |