Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

Vous n'avez pas encore de compte Developpez.com ? L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Developpez.com

Qt

Choisissez la catégorie, puis la rubrique :

Viadeo Twitter Facebook Share on Google+   
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

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 les fonctionnalités définies dans un fichier source C++ (par exemple, lors de l'utilisation d'un modèle de données Qt en C++ ou lors de l'appel de fonctions d'une bibliothèque C++ tierce) ;
  • pour accéder aux fonctionnalités du module Qt Declarative (par exemple, pour générer des images dynamiquement en utilisant QDeclarativeImageProvider) ;
  • pour écrire vos propres éléments QML (que ce soit pour votre application ou pour distribuer à d'autres).

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 module

Le 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.

  • QDeclarativeEngine : un moteur QML fournissant un environnement pour exécuter le code QML. Chaque application nécessite au moins une instance de ce moteur.
  • QDeclarativeContext : un contexte permettant à l'application d'exposer les données aux composants QML créés par un moteur.

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 :

  • charger un composant QML et l'utiliser (ou ses enfants) à partir du C++ ;
  • intégrer un objet C++ et ses propriétés directement dans un composant QML (par exemple, pour rendre un objet C++ particulier appelable à partir du QML ou pour remplacer un modèle de liste factice avec un ensemble de données réelles) ;
  • définir de nouveaux éléments QML (à travers les classes C++ basées sur QObject) et les créer directement dans votre code QML.

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() :

 // Utilise QDeclarativeComponent
 
 QDeclarativeEngine engine;
 
 QDeclarativeComponent component(&engine,
 
         QUrl::fromLocalFile("MyItem.qml"));
 
 QObject *object = component.create();
 
 ...
 
 delete object;
 // Utilise QDeclarativeView
 
 QDeclarativeView view;
 
 view.setSource(QUrl::fromLocalFile("MyItem.qml"));
 
 view.show();
 
 QObject *object = view.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 QML

Lors 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 :

 class ApplicationData : public QObject
 
 {
 
     Q_OBJECT
 
 public:
 
     Q_INVOKABLE QDateTime getCurrentDateTime() const {
 
         return QDateTime::currentDateTime();
 
     }
 
 };
 
 
 
 int main(int argc, char *argv[]) {
 
     QApplication app(argc, argv);
 
 
 
     QDeclarativeView view;
 
 
 
     ApplicationData data;
 
     view.rootContext()->setContextProperty("applicationData", &data);
 
 
 
     view.setSource(QUrl::fromLocalFile("MyItem.qml"));
 
     view.show();
 
 
 
     return app.exec();
 
 }
 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Text { text: applicationData.getCurrentDateTime() }

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 QML

Bien 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 fonctions

Les 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 :

 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Item {
 
     function myQmlFunction(msg) {
 
         console.log("Got message:", msg)
 
         return "some return value"
 
     }
 
 }
 // main.cpp
 
 QDeclarativeEngine engine;
 
 QDeclarativeComponent component(&engine, "MyItem.qml");
 
 QObject *object = component.create();
 
 
 
 QVariant returnedValeur;
 
 QVariant msg = "Hello from C++";
 
 QMetaObject::invokeMethod(object, "myQmlFunction",
 
         Q_RETURN_ARG(QVariant, returnedValeur),
 
         Q_ARG(QVariant, msg));
 
 
 
 qDebug() << "QML function returned:" << returnedValeur.toString();
 
 delete object;

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() :

 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Item {
 
     width: 100; height: 100
 
 
 
     MouseArea {
 
         anchors.fill: parent
 
         onClicked: {
 
             myObject.cppMethod("Hello from QML")
 
             myObject.cppSlot(12345)
 
         }
 
     }
 
 }
 class MyClass : public QObject
 
 {
 
     Q_OBJECT
 
 public:
 
     Q_INVOKABLE void cppMethod(const QString &msg) {
 
         qDebug() << "Called the C++ method with" << msg;
 
     }
 
 
 
 public slots:
 
     void cppSlot(int number) {
 
         qDebug() << "Called the C++ slot with" << number;
 
     }
 
 };
 
 
 
 int main(int argc, char *argv[]) {
 
     QApplication app(argc, argv);
 
 
 
     QDeclarativeView view;
 
     MyClass myClass;
 
     view.rootContext()->setContextProperty("myObject", &myClass);
 
 
 
     view.setSource(QUrl::fromLocalFile("MyItem.qml"));
 
     view.show();
 
 
 
     return app.exec();
 
 }

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 signaux

Tous 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é :

 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Item {
 
     id: item
 
     width: 100; height: 100
 
 
 
     signal qmlSignal(string msg)
 
 
 
     MouseArea {
 
         anchors.fill: parent
 
         onClicked: item.qmlSignal("Hello from QML")
 
     }
 
 }
 class MyClass : public QObject
 
 {
 
     Q_OBJECT
 
 public slots:
 
     void cppSlot(const QString &msg) {
 
         qDebug() << "Called the C++ slot with message:" << msg;
 
     }
 
 };
 
 
 
 int main(int argc, char *argv[]) {
 
     QApplication app(argc, argv);
 
 
 
     QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
 
     QObject *item = view.rootObject();
 
 
 
     MyClass myClass;
 
     QObject::connect(item, SIGNAL(qmlSignal(QString)),
 
                      &myClass, SLOT(cppSlot(QString)));
 
 
 
     view.show();
 
     return app.exec();
 
 }

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 :

 class ImageViewer : public QDeclarativeItem
 
 {
 
     Q_OBJECT
 
     Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
 
 public:
 
     ...
 
 signals:
 
     void imageChanged();
 
     void loadingError(const QString &errorMsg);
 
 };
 ImageViewer {
 
     onImageChanged: console.log("Image changed!")
 
     onLoadingError: console.log("Image failed to load:", errorMsg)
 
 }

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 :

 ImageViewer viewer;
 
 
 
 QDeclarativeView view;
 
 view.rootContext()->setContextProperty("imageViewer", &viewer);
 
 
 
 view.setSource(QUrl::fromLocalFile("MyItem.qml"));
 
 view.show();
 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Item {
 
     Connections {
 
         target: imageViewer
 
         onImageChanged: console.log("Image has changed!")
 
     }
 
 }

Modifier les propriétés

N'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 :

 class ApplicationData : public QObject
 
 {
 
     Q_OBJECT
 
     Q_PROPERTY(QColor backgroundColor
 
             READ backgroundColor
 
             WRITE setBackgroundColor
 
             NOTIFY backgroundColorChanged)
 
 
 
 public:
 
     void setBackgroundColor(const QColor &c) {
 
         if (c != m_color) {
 
             m_color = c;
 
             emit backgroundColorChanged();
 
         }
 
     }
 
 
 
     QColor backgroundColor() const {
 
         return m_color;
 
     }
 
 
 
 signals:
 
     void backgroundColorChanged();
 
 
 
 private:
 
     QColor m_color;
 
 };
 // MyItem.qml
 
 import QtQuick 1.0
 
 
 
 Rectangle {
 
     width: 100; height: 100
 
     color: applicationData.backgroundColor
 
 
 
     MouseArea {
 
         anchors.fill: parent
 
         onClicked: applicationData.backgroundColor = "red"
 
     }
 
 }

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és

Toutes 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 :

  • bool ;
  • unsigned int, int ;
  • float, double, qreal ; * QString ; * QUrl ; * QColor ; * QDate, QTime, QDateTime ; * QPoint, QPointF ; * QSize, QSizeF ; * QRect, QRectF ; * QVariant ; * QVariantList, QVariantMap ; * QObject* ; * énumérations déclarées avec Q_ENUMS(). Pour permettre un type C++ personnalisé d'être créé ou utilisé en QML, la classe C++ doit être enregistrée comme type QML avec la fonction qmlRegisterType(), comme présenté dans la section Définir de nouveaux éléments QML ci-dessus. === Tableaux et objets JavaScript === Il existe une gestion intégrée de la conversion automatique des types entre QVariantList et les tableaux JavaScript, et entre QVariantMap et les objets JavaScript. Par exemple, la fonction définie dans le code QML ci-dessous attend deux arguments, un tableau et un objet puis affiche leur contenu en utilisant la syntaxe standard JavaScript pour les tableaux et les éléments objets. Le code C++ ci-dessous appelle la fonction, en passant un QVariantList et un QVariantMap, qui sont automatiquement convertis en respectivement un tableau JavaScript et un objet : | <code qml> MyItem.qml Item { function readValeurs(anArray, anObject) { for (var i=0; i<anArray.length; i++) console.log(« Array item: », anArray[i]) for (var prop in anObject) { console.log(« Object item: », prop,  »= », anObject[prop]) } } }</code> | <code cpp-qt> C++ QDeclarativeView view(QUrl::fromLocalFile(« MyItem.qml »)); QVariantList list; list << 10 << Qt::green << « bottles »; QVariantMap map; map.insert(« language », « QML »); map.insert(« released », QDate(2010, 9, 21)); QMetaObject::invokeMethod(view.rootObject(), « readValues », Q_ARG(QVariant, QVariant::fromValue(list)), Q_ARG(QVariant, QVariant::fromValue(map)));</code> | La sortie du programme est la suivante : <code cpp-qt> Array item: 10 Array item: #00ff00 Array item: bottles Object item: language = QML Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)</code> De façon similaire, si un type C++ utilise un type QVariantList ou QVariantMap pour une propriété ou un paramètre de méthode, la valeur peut être créée à partir d'un tableau JavaScript ou d'un objet dans la partie QML et sera automatiquement convertie en un QVariantList ou QVariantMap lorsqu'il est passé au C++. === Utilisation des énumérations pour un type personnalisé === Pour utiliser une énumération à partir d'un composant C++ personnalisé, l'énumération doit être déclarée avec Q_ENUMS() pour l'enregistrer dans le système de métaobjets. Par exemple, le type C++ suivant contient une énumération Status : <code cpp-qt> class ImageViewer : public QDeclarativeItem { Q_OBJECT Q_ENUMS(Status) Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: enum Status { Ready, Loading, Error }; Status status() const; signals: void statusChanged(); };</code> À condition que la classe ImageViewer ait été enregistrée avec la fonction qmlRegisterType(), son énumération Status peut maintenant être utilisée en QML : <code cpp-qt> ImageViewer { onStatusChanged: { if (status == ImageViewer.Ready) console.log(« Image viewer is ready! ») } }</code> Le type C++ doit être enregistré dans QML pour permettre d'utiliser ses énumérations. Si votre type C++ n'est pas instanciable, il peut être enregistré en utilisant la fonction qmlRegisterUncreatableType(). Pour être accessibles à partir du QML, le nom des énumérations doit commencer par une lettre capitale. Voir le tutoriel écriture d'extensions QML en C++ et la documentation de référence étendre QML en C++ pour plus d'informations. === Conversion automatique des types à partir de chaînes de caractères === Pour plus de facilité, certains types de base peuvent être spécifiés en QML avec des chaînes de caractères afin qu'il soit plus facile de passer des valeurs simples de QML au C++. ^ Type ^ Format de chaîne^ Exemple ^ | QColor | Color name,  »#RRGGBB »,  »#RRGGBBAA » | « red »,  »#ff0000 »,  »#ff000000 » | | QDate | « YYYY-MM-DD » | « 2010-05-31 » | | QPoint | « x,y » | « 10,20 » | | QRect | « x,y,WidthxHeight » | « 50,50,100 × 100 » | | QSize | « WidthxHeight » | « 100 × 200 » | | QTime | « hh:mm:ss » | « 14:22:55 » | | QUrl | URL string | « http://www.example.com » | | QVector3D | « x,y,z » | « 0,1,0 » | | Valeur d'énumération | Nom de valeur de l'énum | « AlignRight » | Vous pourrez trouver plus de détails sur ces formats dans la documentation des types de base. Ces formats de chaînes de caractères peuvent être utilisés pour définir des valeurs de propriétés QML et comme arguments de fonctions C++. Cela est présenté dans de multiples exemples sur cette page ; dans l'exemple de propriétés ci-dessus, la classe ApplicationData possède une propriété backgroundColor de type QColor, qui est définie à partir du code QML avec la chaîne de caractères « red » au lieu d'un objet QColor. S'il est préférable de passer une valeur explicitement typée plutôt qu'une chaîne de caractères, l'objet Qt global fournit des fonctions utilitaires afin de créer certains types d'objets listés ci-dessus. Par exemple, Qt.rgba() crée un QColor à partir de quatre valeurs RGBA. Le QColor retourné par cette fonction peut être utilisé à la place de la chaîne de caractères pour définir une propriété de type QColor ou pour appeler une fonction C++ qui requiert un paramètre QColor. ==== Écriture de plug-ins QML ==== Le module Qt Declarative inclut la classe QDeclarativeExtensionPlugin, qui est une classe abstraite pour écrire des plug-ins QML. Cela permet à des extensions QML d'être chargées dynamiquement dans les applications QML. Voir la documentation QDeclarativeExtensionPlugin et comment créer des plug-ins Qt pour plus de détails. ==== Gestion des fichiers de ressources avec le système de ressources de Qt ==== Le système de ressource de Qt permet à des fichiers ressources d'être inclus dans les fichiers binaires d'une application exécutable. Cela peut être utile lors de la construction d'application QML/C++ car cela permet aux fichiers QML (comme toutes les autres ressources telles que les images et les fichiers sons) de pouvoir être utilisés avec le système d'URI plutôt que d'utiliser des chemins relatifs ou absolus. Notez que si vous utilisez le système de ressources, l'application doit être recompilée à chaque fois qu'un fichier source QML est modifié afin de mettre à jour les ressources du paquetage. Pour utiliser le système de ressources dans une application QML/C++, il faut : * créer un fichier de ressources .qrc qui liste les fichiers de ressources dans un format XML ; * à partir du C++, charger le fichier QML principal comme ressource en utilisant le préfixe :/ ou comme URL avec le schéma qrc. Une fois que cela est fait, tous les fichiers spécifiés par des chemins relatifs dans QML seront chargés à partir du système de ressources. L'utilisation du système de ressources est transparente pour la couche QML ; cela signifie que tout code QML doit se référer à des fichiers en utilisant des chemins relatifs et ne doit pas utiliser le schéma qrc. Ce schéma doit être utilisé seulement dans le code C++ se référant aux fichiers des ressources. Voici une application construite en utilisant le système de ressources de Qt. La hiérarchie du répertoire est le suivant: <code cpp-qt> project |- example.qrc |- main.qml |- images |- background.png |- main.cpp |- project.pro</code> Les fichiers main.qml et background.png seront inclus comme fichiers de ressources. Ceci est effectué dans le fichier de ressource example.qrc : <code xml> <!DOCTYPE RCC> <RCC version=« 1.0 »> <qresource prefix= »/ »> <file>main.qml</file> <file>images/background.png</file> </qresource> </RCC></code> Étant donné que le fichier background.png est une ressource, le fichier main.qml doit se référer à celui-ci en utilisant le chemin relatif spécifié dans example.qrc: <code qml> main.qml import QtQuick 1.0 Image { source: « images/background.png » }</code> Pour permettre au QML de trouver le fichier de ressources, le fichier main.cpp charge le fichier QML principal, main.qml, comme fichier de ressources en utilisant le schéma qrc : <code cpp-qt> int main(int argc, char *argv[]) { QApplication app(argc, argv); QDeclarativeView view; view.setSource(QUrl(« qrc:/main.qml »)); view.show(); return app.exec(); }</code> Finalement, le fichier project.pro utilise la variable RESOURCES pour indiquer que le fichier example.qrc doit être utilisé pour construire les ressources de l'application : <code cpp-qt> QT += declarative SOURCES += main.cpp RESOURCES += example.qrc</code> Voir le système de ressources Qt pour plus d'informations. ==== Remerciements ==== Merci à Alexandre Laurent pour la traduction, ainsi que Ilya Diallo, Dimitry Ernot et Claude Leloup pour la relecture !
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 © 2020 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, 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 !
Responsable bénévole de la rubrique Qt : Thibaut Cuvelier -

Partenaire : Hébergement Web