Auf dieser Seite

Qt Protobuf QML-Typen

Mit dem Generator-Plugin können Sie Protobuf-Nachrichten in QML registrieren. Verwenden Sie zur Registrierung des Typs die Generierungsschlüssel „ QML “ und „ QML_URI “. Weitere Informationen finden Sie in den API-Details zum Befehl „qt_add_protobuf()“ sowie im Beispiel zur API-Verwendung „QML extended protobuf“.

Registrierte Protobuf-Nachrichten stehen in QML zur Verfügung, genau wie die integrierten „ Q_GADGET “-Typen. Die Registrierung erfolgt über das QML-Modul.

Verwendung von Protobuf-Nachrichten in QML

Verwenden Sie das Generator-Plugin, um Bibliotheken mit Protobuf-Nachrichten zu generieren, auf die Sie aus „ Qt Quick “-Anwendungen zugreifen können. Die „Qt Protobuf “-CMake-API verfügt über entsprechende Optionen, die die Erstellung des QML-Moduls steuern.

Beispielsweise gibt es das „ userdb.proto “-Protobuf-Schema, das die „ User “-Nachricht enthält:

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;
}

Um die Nachricht „ User “ in QML verfügbar zu machen, verwenden Sie das Protobuf-Schema und den Befehl `qt_add_protobuf()` mit dem 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)

Die Funktion `qt_add_protobuf() ` generiert eine Bibliothek namens ` userdb_gen`, die die Protobuf-Nachrichten aus ` userdb.proto ` mit QML-Unterstützung enthält. Um die Nachrichten in QML zu verwenden, importieren Sie das generierte QML-Modul über die URI, die im Argument ` QML_URI ` des Aufrufs ` qt_add_protobuf ` angegeben ist:

import userdb.pb

Alle Protobuf-Nachrichten sind als QML-Werttypen registriert. Um sie in QML zu verwenden, definieren Sie das Attribut „property“ für ein beliebiges QML-Element:

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

Um die Felder „ type “, „ name “ oder „ email “ der Eigenschaft „ newUser “ zu ändern, verwenden Sie QML-Signal-Callbacks. Beispiel:

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

Die Enum-Werte von ` User.Type ` sind auch aus QML heraus zugänglich. Das folgende Beispiel zeigt, wie man ein ` ComboBox `-Element unter Verwendung der Enum-Werte erstellt:

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
    }
}

Integration von QML und C++

In QML registrierte C++-Klassen können die in QML erstellten Nachrichten sowohl in Eigenschaften als auch in aufrufbaren Methoden verwenden.

Das Singleton-QML-Objekt ` UserDBEngine ` stellt die Eigenschaft ` lastAddedUser ` und die aufrufbare Methode ` addUser ` für QML bereit:

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);
    ...
}

Die Eigenschaft ` lastAddedUser ` hat den Typ ` userdb::User `, der aus dem Schema ` userdb.proto ` aus dem vorherigen Abschnitt generiert wurde. Die aufrufbare Methode ` addUser ` akzeptiert eine Konstantenreferenz auf ein Objekt vom Typ ` userdb::User `. Sowohl die Eigenschaft als auch die Methode können von QML aus verwendet werden:

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
}

Doppelte Protobuf-Nachrichten

Sie sollten die Deklaration doppelter Protobuf-Nachrichten in Ihren „ *.proto “-Dateien vermeiden oder mit Bedacht vorgehen. Wenn Ihre Anwendung mehrere identische Protobuf-Nachrichtennamen verwendet, die in verschiedenen Protobuf-Paketen deklariert sind, können diese im automatisch generierten Code zu Konflikten führen. Im folgenden Beispiel verwenden zwei verschiedene Proto-Pakete, „ qtprotobufnamespace “ und „ qtprotobufnamespace1.nested “, dieselbe Proto-Nachricht „ NestedFieldMessage “. Die Datei „ nested.proto “:

syntax = "proto3";

package qtprotobufnamespace;
import "externalpackage.proto";

message NestedFieldMessage {
    sint32 testFieldInt = 1;
}

Die Datei „ nestedspace1.proto “:

syntax = "proto3";

package qtprotobufnamespace1.nested;

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

Falls sich Namensduplikate zwischen den Paketen nicht vermeiden lassen, platzieren Sie die doppelten Nachrichten in verschiedenen QML-Modulen und verwenden Sie für jeden QML-Modul-Import einen <Qualifier>, siehe Modul- (Namespace-)Importe. Nachfolgend ein Beispiel dafür, wie Protobuf-Pakete in verschiedene QML-Module eingefügt werden können:

# 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"
)

Beispiel für die Verwendung von <Qualifier>:

import qtprotobufnamespace as NestedFieldMessages
import qtprotobufnamespace1.nested as FieldMessages_Nested1

...

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

Hinweis: Die Verwendung von Duplikaten löst bei der Kompilierung eine Warnung aus.

Doppelte QML-Typen

Wenn Ihre Anwendung Protobuf-Nachrichten mit Namen verwendet, die in QML bereits als QML-Typen reserviert sind, kann das korrekte Verhalten nicht garantiert werden, und es wird der Fehler „ Element is not creatable “ ausgelöst. Um eine Überschneidung von QML-Typen zu verhindern, verwenden Sie einen <Qualifier> für den Import von QML-Modulen (siehe „Modul-(Namespace-)Importe“). Beispielsweise würden die folgenden Protobuf-Nachrichten beim Import in den globalen Namensraum mit den QML-Typen „ Text “ und „ Item “ in Konflikt geraten:

syntax = "proto3";
package test.example;

message Text {
    string text = 1;
}

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

Verwenden Sie das Makro ` qt_add_protobuf()` mit der Option ` QML `, um die Generierung von QML-Typen aus den oben genannten Protobuf-Nachrichten zu aktivieren. Siehe das folgende Beispiel:

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

Kollisionen mit den QML-Typen treten auf, wenn Protobuf-Nachrichten nach dem Import von „ QtQuick “ in einen globalen Namensraum importiert werden. Siehe das folgende Beispiel:

 import QtQuick
 import test.example

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

Um Konflikte mit den QML-Typen zu vermeiden, verwenden Sie „ <Qualifier> “, um das generierte QML-Modul in einen lokalen Namensraum zu importieren. Siehe das folgende Beispiel:

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

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

Umgang mit QML-Schlüsselwörtern

Achten Sie auf Schlüsselwörter, die im QML- oder JavaScript-Kontext reserviert sind, im *.proto-Kontext jedoch nicht. Felder mit Namen, die von QML reserviert sind, werden vom Generator-Plugin stillschweigend um das Suffix „ _proto “ erweitert. Beispielsweise sind „ id “, „ property “ und „ import “ reservierte Schlüsselwörter. Sie werden durch „ id_proto “, „ property_proto “ und „ import_proto “ ersetzt:

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

Ausgabe des generierten Codes:

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

Außerdem dürfen Enum-Werte nicht mit einem Kleinbuchstaben beginnen. Das Generator-Plugin schreibt den ersten Buchstaben in der Code-Ausgabe groß. Siehe das folgende Beispiel „ *.proto “:

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

Generierte Codeausgabe:

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

Außerdem dürfen Enum-Felder nicht mit einem Unterstrich beginnen. Solche Felder werden zwar unverändert generiert, sind jedoch im QML undefiniert, es sei denn, die QML-Engine erlaubt in Zukunft deren Registrierung. Siehe das folgende Beispiel „ *.proto “:

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

Generierte Ausgabe:

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

Weitere Informationen zur Syntax von QML-Eigenschaften finden Sie unter „Definieren von Eigenschaftsattributen“.

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