Qt Protobuf QML 类型
使用生成器插件,您可以在 QML 中注册 protobuf 消息。要注册类型,请使用 QML
和 QML_URI
生成密钥。在 qt_add_protobuf 命令和 API 用例 QML 扩展 protobuf 中查看 API 详细信息。
注册的 protobuf 消息在 QML 中可用,就像内置的 Q_GADGET 类型一样。注册是通过 QML 模块完成的。
在 QML 中使用 protobuf 消息
使用生成器插件生成 protobuf 消息库,您可以从 Qt Quick 应用程序中访问它。Qt Protobuf CMake API 有相应的选项来控制 QML 模块创建。
例如,您有包含 User
消息的 userdb.proto
protobuf 架构
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; }
要在外部 QML 中排除 User
消息,请使用 protobuf 架构和 qt_add_protobuf 命令,带有 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)
qt_add_protobuf 函数将生成一个名为 userdb_gen
的库,其中包含从 userdb.proto
中生成的 protobuf 消息(具有 QML 支持)。要在 QML 中使用这些消息,使用 qt_add_protobuf 调用的 QML_URI
参数中指定的 URI 引入生成的 QML 模块
import userdb.pb
所有 protobuf 消息都注册为 QML 值类型。要在 QML 中使用它们,为某个 QML 项目定义 属性属性。
Window { id: userAddForm property user newUser ... }
要更改 newUser
属性的 type
、name
或 email
字段,请使用 QML 信号回调。例如
TextField { id: userNameField onTextChanged: { userAddForm.newUser.name = userNameField.text } } ... TextField { id: userEmailField onTextChanged: { userAddForm.newUser.email = userEmailField.text } }
User.Type
枚举值也可以从 QML 访问。以下示例演示如何使用枚举值创建 ComboBox 项
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 } }
集成 QML 和 C++
在 QML 中注册的 C++ 类可以在属性和可调用的方法中使用在 QML 中创建的消息。
单例 QML 对象 UserDBEngine
将 lastAddedUser
属性和可调用的 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); ... }
lastAddedUser
属性具有从先前部分中生成的 userdb::User
类型(来自 userdb.proto
架构)。可调用的 addUser
方法接受对 userdb::User
类型对象的常数引用。属性和方法都可以从 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 }
Protobuf 消息重复
您应在您的 *.proto
文件中避免声明protobuf消息重复,或者智慧地处理它们。如果您的应用程序在使用不同protobuf包中声明了多个相同的protobuf消息名称,它们可能在自动生成的代码中出现冲突。以下示例中,两个不同的proto包 qtprotobufnamespace
和 qtprotobufnamespace1.nested
使用了相同的proto消息 NestedFieldMessage
。文件 nested.proto
中包含了这种情况。
syntax = "proto3"; package qtprotobufnamespace; import "externalpackage.proto"; message NestedFieldMessage { sint32 testFieldInt = 1; }
文件 nestedspace1.proto
syntax = "proto3"; package qtprotobufnamespace1.nested; message NestedFieldMessage { message NestedMessage { sint32 field = 1; } NestedMessage nested = 1; }
如果无法避免包之间的名称重复,那么请将重复的消息放在不同的QML模块中,并为每个QML模块的导入使用一个 <Qualifier>,请参阅 模块(命名空间)导入。以下是如何将protobuf包添加到不同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" )
<Qualifier> 的使用示例
import qtprotobufnamespace as NestedFieldMessages import qtprotobufnamespace1.nested as FieldMessages_Nested1 ... property NestedFieldMessages.nestedFieldMessage fieldMsg1; property FieldMessages_Nested1.nestedFieldMessage fieldMsg2;
注意:在编译时间使用重复将触发一个警告。
QML关键字处理
请注意,在QML或JavaScript上下文中保留但不在 *.proto 上下文中保留的关键字。具有QML保留名称的字段将被 _proto
后缀静默扩展,由 生成插件 完成。例如,id
、property
和 import
是保留关键字。它们将被替换为 id_proto
、property_proto
、import_proto
。
message MessageUpperCaseReserved { sint32 Import = 1; sint32 Property = 2; sint32 Id = 3; }
生成代码输出
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 ...)
此外,枚举值不能以下划线字母开头。生成插件将代码输出中的第一个字母转换为大写。以下是一个 *.proto
示例
enum LowerCaseEnum { enumValue0 = 0; enumValue1 = 1; enumValue2 = 2; }
生成代码输出
enum LowerCaseEnum { EnumValue0 = 0, EnumValue1 = 1, EnumValue2 = 2, }; Q_ENUM(LowerCaseEnum)
此外,枚举字段不能以下划线符号开头。此类字段将被原样生成,但在QML中未经定义,除非QML引擎将来允许注册它们。以下是一个 *.proto
示例
enum UnderScoreEnum { _enumUnderscoreValue0 = 0; _EnumUnderscoreValue1 = 1; }
生成输出
enum UnderScoreEnum { _enumUnderscoreValue0 = 0, _EnumUnderscoreValue1 = 1, }; Q_ENUM(UnderScoreEnum)
有关QML属性语法的更多信息,请查看 定义属性属性。
© 2024 Qt公司有限公司。包含在此处的文档贡献的版权属于其所有者。此处提供的文档是根据自由软件基金会发布的 GNU自由文档许可版本1.3 的条款许可的。Qt及其相关徽标是芬兰的Qt公司及其全球子公司和分公司的商标。所有其他商标均为其所有者的财产。