Qt Protobuf QML-Typen

Mit dem Generator-Plugin können Sie Protobuf-Nachrichten in QML registrieren. Um den Typ zu registrieren, verwenden Sie die Generierungsschlüssel QML und QML_URI. Siehe API-Details in qt_add_protobuf Befehl und API-Verwendungsbeispiel QML extended protobuf.

Registrierte Protobuf-Nachrichten sind in der QML verfügbar, wie die eingebauten Q_GADGET Typen. Die Registrierung erfolgt über das QML-Modul.

Verwendung von Protobuf-Nachrichten in QML

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

Sie haben zum Beispiel 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 User -Nachricht in QML darzustellen, 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 erzeugt eine Bibliothek namens userdb_gen, die die protobuf-Nachrichten von userdb.proto mit QML-Unterstützung enthält. Um die Nachrichten in QML zu verwenden, importieren Sie das generierte QML-Modul unter Verwendung der URI, die im Argument QML_URI des qt_add_protobuf -Aufrufs angegeben ist:

import userdb.pb

Alle protobuf-Nachrichten sind als QML Value Types registriert. Um sie in QML zu verwenden, definieren Sie das Property-Attribut für ein QML-Element:

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

Um die Felder type, name oder email der Eigenschaft newUser zu ändern, verwenden Sie QML-Signalaufrufe. Ein Beispiel:

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

Die User.Type enum-Werte sind auch über QML zugänglich. Das folgende Beispiel zeigt, wie ein ComboBox Element unter Verwendung der Enum-Werte erstellt werden kann:

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 zur Verfügung:

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

Protobuf-Nachrichten-Duplikate

Sie sollten die Deklaration von Protobuf-Nachrichtenduplikaten in Ihren *.proto Dateien vermeiden oder mit Bedacht vornehmen. Wenn Ihre Anwendung mehrere identische Protobuf-Nachrichtennamen verwendet, die in verschiedenen Protobuf-Paketen deklariert sind, könnten sie sich im automatisch generierten Code widersprechen. Im folgenden Beispiel verwenden zwei verschiedene Proto-Pakete, qtprotobufnamespace und qtprotobufnamespace1.nested, die gleiche 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 es keine Möglichkeit gibt, Namensduplikate zwischen Paketen zu vermeiden, dann legen Sie die doppelten Nachrichten in verschiedene QML-Module und verwenden Sie einen <Qualifier> für jeden QML-Modul-Import, siehe Modul (Namespace) Importe. Nachfolgend das Beispiel, wie man protobuf-Pakete in verschiedene QML-Module einfügt:

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

Das <Qualifier>-Verwendungsbeispiel:

import qtprotobufnamespace as NestedFieldMessages
import qtprotobufnamespace1.nested as FieldMessages_Nested1

...

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

Hinweis: Die Verwendung von Duplikaten führt zu einer Warnung zur Kompilierungszeit.

QML-Typen Duplikate

Wenn Ihre Anwendung Protobuf-Nachrichten mit Namen verwendet, die bereits in QML als QML-Typen reserviert sind, kann das korrekte Verhalten nicht garantiert werden, und Element is not creatable würde einen Fehler auslösen. Um eine Überschneidung von QML-Typen zu verhindern, verwenden Sie einen <Qualifier> für den QML-Modulimport, siehe Modul-(Namensraum)-Importe. Zum Beispiel würden die folgenden protobuf-Nachrichten mit den QML-Typen Text und Item kollidieren, wenn sie in den globalen Namespace importiert werden:

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 Erzeugung von QML-Typen aus den obigen Protobuf-Nachrichten zu aktivieren. Siehe das Beispiel unten:

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

Konflikte mit den QML-Typen werden ausgelöst, wenn protobuf-Nachrichten nach dem QtQuick -Import in einen globalen Namespace importiert werden. Siehe das unten stehende Beispiel:

 import QtQuick
 import test.example

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

Um Konflikte mit den QML-Typen zu vermeiden, verwenden Sie ein <Qualifier>, um das generierte QML-Modul in einen lokalen Namespace zu importieren. Siehe das unten stehende 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 die Schlüsselwörter, die im QML- oder JavaScript-Kontext reserviert sind, aber nicht im *.proto-Kontext. Felder mit Namen, die von QML reserviert sind, werden vom Generator-Plugin stillschweigend um das Suffix _proto erweitert. Zum Beispiel sind id, property und import reservierte Schlüsselwörter. Sie werden durch id_proto, property_proto, import_proto ersetzt:

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

Generierte Code-Ausgabe:

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 wird den ersten Buchstaben in der Code-Ausgabe groß schreiben. Siehe das Beispiel *.proto unten:

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

Generierte Code-Ausgabe:

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

Außerdem können Enum-Felder nicht mit einem Unterstrich beginnen. Solche Felder werden so generiert, wie sie sind, sind aber in der QML undefiniert, es sei denn, die QML-Engine erlaubt es, sie in Zukunft zu registrieren. Siehe das *.proto Beispiel unten:

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

Generierte Ausgabe:

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

Weitere Informationen über die Syntax von QML-Eigenschaften finden Sie unter Definieren von Eigenschaftsattributen.

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