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公司及其全球子公司和分公司的商标。所有其他商标均为其所有者的财产。