Qt Protobuf QMLタイプ

ジェネレータプラグインを使うと、QMLにprotobufメッセージを登録することができます。型を登録するには、QMLQML_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;
}

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.proto の protobuf メッセージを QML でサポートしたuserdb_gen というライブラリを生成します。QML でメッセージを使用するには、qt_add_protobufQML_URI 引数で指定された URI を使用して、生成された QML モジュールをインポートしてください:

import userdb.pb

すべてのprotobufメッセージはQMLの値型として登録されています。QMLでこれらを使用するには、QMLの項目にproperty属性を定義します:

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

newUser プロパティのtypenameemail フィールドを変更するには、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メッセー ジ名を複数使用すると、自動生成されるコードの中で矛盾が生じる可能性があります。以下の例では、qtprotobufnamespaceqtprotobufnamespace1.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ですでに予約されている名前のprotobufメッセージをQML型として使用する場合、正しい動作が保証されず、Element is not creatable 。QML型の重複を防ぐためには、QMLモジュールのインポートに<Qualifier>を使用してください。例えば、以下のprotobufメッセージは、グローバル名前空間にインポートした場合、TextItem のQMLタイプと衝突してしまいます:

syntax = "proto3";
package test.example;

message Text {
    string text = 1;
}

message Item {
    sint32 width = 1;
    sint32 height = 2;
}

qt_add_protobufマクロにQML オプションをつけて、上記の protobuf メッセージから QML タイプを生成できるようにしてください。以下の例を参照してください:

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

protobufメッセージがQtQuick インポート後にグローバル名前空間にインポートされた場合、QML型との衝突が発生します。以下の例を参照してください:

 import QtQuick
 import test.example

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

QML 型との衝突を避けるには、<Qualifier> を使用して、生成された QML モジュールをローカル名前空間にインポートしてください。以下の例を参照してください:

// No qualifier - global namespace
import QtQuick
// ProtobufMessages - a qualifier of local namespace.
import test.example as ProtobufMessages

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

QMLキーワードの取り扱い

QML や JavaScript では予約されているが、*.proto では予約されていないキーワードに 注意してください。QMLで予約されている名前のフィールドは、ジェネレータプラグインによって_proto というサフィックスによって無言で拡張されます。例えば、idpropertyimport は予約されたキーワードです。これらは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 プロパティの構文についての詳細は、「プロパティ属性の定義」を参照してください。

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