Qt Protobuf QMLタイプ
ジェネレータプラグインを使うと、QMLにprotobufメッセージを登録することができます。型を登録するには、QML
とQML_URI
の生成キーを使います。APIの詳細はqt_add_protobufコマンドとAPI使用例QML extended protobufを参照してください。
登録されたprotobufメッセージは、組み込みのQ_GADGET 型と同様にQMLで利用可能です。登録はQMLモジュールを介して行われます。
QMLでのprotobufメッセージの利用
ジェネレータプラグインを使用して、Qt Quickアプリケーションからアクセスできるprotobufメッセージのライブラリを生成します。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; }
User
メッセージを QML で公開するには、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.proto
の protobuf メッセージを QML でサポートしたuserdb_gen
というライブラリを生成します。QML でメッセージを使用するには、qt_add_protobuf
のQML_URI
引数で指定された URI を使用して、生成された QML モジュールをインポートしてください:
import userdb.pb
すべてのprotobufメッセージはQMLの値型として登録されています。QMLでこれらを使用するには、QMLの項目にproperty属性を定義します:
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.proto
スキーマから生成されたuserdb::User
型を持っています。呼び出し可能な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メッセー ジ名を複数使用すると、自動生成されるコードの中で矛盾が生じる可能性があります。以下の例では、qtprotobufnamespace
とqtprotobufnamespace1.nested
という 2 つの異なる proto パッケージが、同じ 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)
また、enum フィールドはアンダースコア記号で始めることはできません。このようなフィールドはそのまま生成されますが、将来QMLエンジンがこのようなフィールドの登録を許可しない限り、QMLの中では未定義となります。以下の*.proto
の例を参照してください:
enum UnderScoreEnum { _enumUnderscoreValue0 = 0; _EnumUnderscoreValue1 = 1; }
生成された出力:
enum UnderScoreEnum { _enumUnderscoreValue0 = 0, _EnumUnderscoreValue1 = 1, }; Q_ENUM(UnderScoreEnum)
QML プロパティの構文についての詳細は、Defining Property Attributes を参照してください。
本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。