Sur cette page

Qt Protobuf Types QML

Avec le plugin generator, vous pouvez enregistrer des messages protobuf dans le QML. Pour enregistrer le type, utilisez les clés de génération QML et QML_URI. Voir les détails de l'API dans la commande qt_add_protobuf et l'exemple d'utilisation de l'API QML extended protobuf.

Les messages protobuf enregistrés sont disponibles dans le QML, comme les types intégrés dans Q_GADGET. L'enregistrement se fait via le module QML.

Utilisation des messages protobuf dans QML

Utilisez le plugin generator pour générer des bibliothèques de messages protobuf auxquelles vous pouvez accéder à partir des applications Qt Quick. L'API CMake deQt Protobuf dispose d'options respectives qui contrôlent la création du module QML.

Par exemple, vous avez le schéma protobuf userdb.proto qui contient le message User:

syntax = "proto3";

package userdb;

message User {
    enum Type {
        Admin = 0;
        Manager = 1;
        Account = 2;
        Director = 3;
    }
    Type type = 1;
    string name = 2;
    string email = 3;
}

Pour exposer le message User en QML, utilisez le schéma protobuf et la commande qt_add_protobuf avec l'argument QML:

qt_add_executable(appuserdb
    ...
)

qt_add_qml_module(appuserdb
    URI userdb
    VERSION 1.0
    QML_FILES
        ...
    SOURCES
        ...
)

qt_add_protobuf(userdb_gen
    QML
    QML_URI "userdb.pb"
    PROTO_FILES
        userdb.proto
)

target_link_libraries(appuserdb PRIVATE userdb_gen)

La fonction qt_add_protobuf génère une bibliothèque appelée userdb_gen, qui contient les messages protobuf de userdb.proto avec le support QML. Pour utiliser les messages en QML, importez le module QML généré en utilisant l'URI spécifié dans l'argument QML_URI de l'appel qt_add_protobuf:

import userdb.pb

Tous les messages protobuf sont enregistrés en tant que types de valeurs QML. Pour les utiliser en QML, définissez l'attribut property pour un élément QML :

Window {
    id: userAddForm
    property user newUser
    ...
}

Pour modifier les champs type, name ou email de la propriété newUser, utilisez les rappels de signaux QML. Par exemple :

TextField {
    id: userNameField
    onTextChanged: {
        userAddForm.newUser.name = userNameField.text
    }
}
...
TextField {
    id: userEmailField
    onTextChanged: {
        userAddForm.newUser.email = userEmailField.text
    }
}

Les valeurs de l'énumération User.Type sont également accessibles à partir de QML. L'exemple ci-dessous montre comment créer un élément ComboBox à l'aide des valeurs de l'énumération :

ComboBox {
    id: userTypeField
    textRole: "key"
    model: ListModel {
        id: userTypeModel
        ListElement { key: "Admin"; value: User.Admin }
        ListElement { key: "Second"; value: User.Manager }
        ListElement { key: "Account"; value: User.Account }
        ListElement { key: "Director"; value: User.Director }
    }
    onActivated: function(index) {
        userAddForm.newUser.type = userTypeModel.get(index).value
    }
}

Intégration de QML et de C++

Les classes C++ enregistrées dans QML peuvent utiliser les messages créés dans QML à la fois dans les propriétés et dans les méthodes invocables.

L'objet singleton QML UserDBEngine expose la propriété lastAddedUser et la méthode invocable addUser à QML :

class UserDBEngine : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON

    Q_PROPERTY(userdb::User lastAddedUser READ lastAddedUser WRITE setLastAddedUser NOTIFY lastAddedUserChanged FINAL)
public:
    ...
    Q_INVOKABLE void addUser(const userdb::User &newUser);
    ...
}

La propriété lastAddedUser a le type userdb::User généré à partir du schéma userdb.proto de la section précédente. La méthode invocable addUser accepte une référence constante à un objet de type userdb::User. La propriété et la méthode peuvent toutes deux être utilisées à partir de QML :

Button {
    text: "Add"
    onClicked: {
        // Use the property created in the previous section
        UserDBEngine.addUser(userAddForm.newUser)
    }
}
...
Text {
    // The text will be updated automatically when lastAddedUser is changed
    text: "Last added user: " + UserDBEngine.lastAddedUser.name
}

Duplicatas de messages protobuf

Vous devez éviter de déclarer des doublons de messages protobuf dans vos fichiers *.proto ou le faire avec discernement. Si votre application utilise plusieurs noms de messages protobuf identiques déclarés dans différents paquets protobuf, ils risquent de se contredire dans le code généré automatiquement. Dans l'exemple ci-dessous, deux paquets protobuf différents, qtprotobufnamespace et qtprotobufnamespace1.nested, utilisent le même message protobuf NestedFieldMessage. Le fichier nested.proto:

syntax = "proto3";

package qtprotobufnamespace;
import "externalpackage.proto";

message NestedFieldMessage {
    sint32 testFieldInt = 1;
}

Le fichier nestedspace1.proto:

syntax = "proto3";

package qtprotobufnamespace1.nested;

message NestedFieldMessage {
    message NestedMessage {
        sint32 field = 1;
    }
    NestedMessage nested = 1;
}

S'il n'est pas possible d'éviter les doublons de noms entre les paquets, placez les messages dupliqués dans différents modules QML et utilisez un <Qualifier> pour chaque importation de module QML, voir Module (Namespace) Imports. L'exemple ci-dessous montre comment ajouter des paquets protobuf dans différents modules QML :

# qtprotobufnamespace QML module
qt_add_protobuf(nestedtypes_qtprotobuf_qml
    PROTO_FILES
        nested.proto
    QML
    QML_URI
        qtprotobufnamespace
    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_gen1"
)

...

# qtprotobufnamespace1.nested QML module
qt_add_protobuf(nestedspace_qml
    PROTO_FILES
        nestedspace1.proto
    QML
    QML_URI
        qtprotobufnamespace1.nested
    OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_gen2"
)

L'exemple d'utilisation de <Qualifier> :

import qtprotobufnamespace as NestedFieldMessages
import qtprotobufnamespace1.nested as FieldMessages_Nested1

...

property NestedFieldMessages.nestedFieldMessage fieldMsg1;
property FieldMessages_Nested1.nestedFieldMessage fieldMsg2;

Remarque : l'utilisation de doublons déclenche un avertissement au moment de la compilation.

Types QML dupliqués

Si votre application utilise des messages protobuf dont les noms sont déjà réservés dans QML en tant que types QML, le comportement correct ne peut être garanti et l'erreur Element is not creatable sera déclenchée. Pour éviter un chevauchement des types QML, utilisez un <Qualifier> pour l'importation de modules QML, voir Importations de modules (espaces de noms). Par exemple, les messages protobuf suivants entreraient en conflit avec les types QML Text et Item lorsqu'ils sont importés dans l'espace de noms global :

syntax = "proto3";
package test.example;

message Text {
    string text = 1;
}

message Item {
    sint32 width = 1;
    sint32 height = 2;
}

Utilisez la macro qt_add_protobuf avec l'option QML pour activer la génération de types QML à partir des messages protobuf ci-dessus. Voir l'exemple ci-dessous :

qt_add_protobuf(example
    PROTO_FILES
        test.proto
    QML
    QML_URI
        test.example
)

Des conflits avec les types QML se produiront si les messages protobuf sont importés dans un espace de noms global après l'importation de QtQuick. Voir l'exemple ci-dessous :

 import QtQuick
 import test.example

 Item {
    id: root
    ...
    property ProtobufMessages.item itemData
}

Pour éviter les conflits avec les types QML, utilisez une adresse <Qualifier> pour importer le module QML généré dans un espace de noms local. Voir l'exemple ci-dessous :

// No qualifier - global namespace
import QtQuick
// ProtobufMessages - a qualifier of local namespace.
import test.example as ProtobufMessages

Item {
    id: root
    ...
    property ProtobufMessages.item itemData
}

Gestion des mots-clés QML

Faites attention aux mots-clés qui sont réservés dans le contexte QML ou JavaScript, mais qui ne sont pas réservés dans le contexte *.proto. Les champs dont les noms sont réservés par QML seront silencieusement étendus par le suffixe _proto par le plugin de génération. Par exemple, id, property, et import sont des mots-clés réservés. Ils seront remplacés par id_proto, property_proto, import_proto:

message MessageUpperCaseReserved {
    sint32 Import = 1;
    sint32 Property = 2;
    sint32 Id = 3;
}

Sortie du code généré :

Q_PROPERTY(QtProtobuf::sint32 import_proto READ import_proto ...)
Q_PROPERTY(QtProtobuf::sint32 property_proto READ property_proto ...)
Q_PROPERTY(QtProtobuf::sint32 id_proto READ id_proto ...)

En outre, les valeurs d'énumération ne peuvent pas commencer par une lettre minuscule. Le plugin du générateur mettra la première lettre en majuscule dans le code généré. Voir l'exemple *.proto ci-dessous :

enum LowerCaseEnum {
    enumValue0 = 0;
    enumValue1 = 1;
    enumValue2 = 2;
}

Code généré en sortie :

enum LowerCaseEnum {
    EnumValue0 = 0,
    EnumValue1 = 1,
    EnumValue2 = 2,
};
Q_ENUM(LowerCaseEnum)

De même, les champs enum ne peuvent pas commencer par un symbole de soulignement. Ces champs seront générés tels quels, mais ne seront pas définis dans le QML, à moins que le moteur QML ne permette de les enregistrer à l'avenir. Voir l'exemple *.proto ci-dessous :

enum UnderScoreEnum {
    _enumUnderscoreValue0 = 0;
    _EnumUnderscoreValue1 = 1;
}

Sortie générée :

enum UnderScoreEnum {
    _enumUnderscoreValue0 = 0,
    _EnumUnderscoreValue1 = 1,
};
Q_ENUM(UnderScoreEnum)

Pour plus d'informations sur la syntaxe des propriétés QML, voir Définir les attributs des propriétés.

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