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.