QMLとC++間のデータ型変換
QMLとC++の間でデータのやり取りが行われる場合、QMLエンジンはQMLやC++で使 うのに適したデータ型に変換します。このため、交換されるデータはエンジンが認識できる型である必要があります。
QML エンジンでは、多くの Qt C++ データ型をビルトインでサポートしています。さらに、カスタムの C++ 型を QML の型システムに登録し、エンジンで利用できるようにすることもできます。
C++ と様々な QML インテグレーションの方法についての詳細は、C++ と QML インテグレーションの概要のページを参照してください。
このページでは、QMLエンジンがサポートするデータ型と、それらがQMLとC++の間でどのように変換されるかについて説明します。
データの所有権
C++からQMLへデータを転送する場合、データの所有権は常にC++にあります。ただし、C++の明示的なメソッド呼び出しからQObject が返された場合は例外です。この場合、QQmlEngine::CppOwnership を指定してQQmlEngine::setObjectOwnership() を呼び出すことで、オブジェクトの所有権が明示的に C++ に残るように設定されていない限り、QML エンジンがオブジェクトの所有権を持ちます。
また、QMLエンジンはQt C++オブジェクトの通常のQObject 親の所有権を尊重し、親を持つQObject インスタンスを削除することはありません。
基本的な Qt データ型
デフォルトでは、QMLは以下のQtデータ型を認識し、C++からQMLに渡される際、またその逆 の場合も、自動的に対応するQMLのデータ型に変換されます:
Qt データ型 | QML 値型 |
ブール | bool |
符号なし int, int | int |
double | double |
float, qreal | real |
QString | string |
QUrl | url |
QColor | color |
QFont | font |
QDateTime | date |
QPoint,QPointF | point |
QSize,QSizeF | size |
QRect,QRectF | rect |
QMatrix4x4 | matrix4x4 |
QQuaternion | quaternion |
QVector2D QVector3D 、QVector4D | vector2d vector3d 、vector4d |
Q_ENUM() で宣言された列挙型 | enumeration |
注意 Qt GUI注:QColor,QFont,QQuaternion,QMatrix4x4 のようなモジュールが提供するクラスは、モジュールがインクルードされている時のみQMLから利用可能です。 Qt Quickモジュールがインクルードされている場合のみ利用可能です。
便宜上、これらの型の多くはQMLの中で文字列の値や、QtQml::Qt オブジェクトが提供する関連するメソッドによって指定することができます。例えば、Image::sourceSize プロパティはsize 型(これは自動的にQSize 型に変換されます)であり、"widthx
height "としてフォーマットされた文字列値、または Qt.size() 関数によって指定することができます:
詳しくはQML Value Typesのドキュメントを参照してください。
QObject派生型
QObject から派生したクラスは、QML の型システムに登録されていれば、QML と C++ 間でデータ交換を行うための型として使用することができます。
QML ではインスタンス化可能な型とインスタンス化不可能な型の両方を登録することが できます。一旦 QML の型として登録されたクラスは、QML と C++ の間でデータ交換を行うためのデータ型として使用することができます。型登録の詳細についてはC++ 型を QML 型システムに登録するを参照してください。
Qt と JavaScript の型変換
QML エンジンには、QML と C++ 間でデータをやり取りする際に、いくつかの Qt 型を関連する JavaScript 型に変換する機能が組み込まれています。これにより、データ値やその属性へのアクセスを提供するカスタム型を実装する必要なく、これらの型を使用し、C++やJavaScriptで受け取ることが可能になります。
(なお、QMLのJavaScript環境では、String
、Date
、Number
などのネイティブJavaScriptのオブジェクトプロトタイプを変更し、追加機能を提供しています。詳しくはJavaScriptホスト環境を参照してください)。
QVariantList と QVariantMap から JavaScript の Array-like と Object へ
QML エンジンは、QVariantList と JavaScript の配列ライク、QVariantMap と JavaScript のオブジェクト間の自動型変換を提供します。
配列ライクとは ECMAScript の用語で、配列のように使われるオブジェクトのことです。QVariantList (および他のC++シーケンシャル・コンテナ)からの変換によって生成されるarray-likeは、それだけではなく、一般的な配列メソッドを提供し、自動的にlengthプロパティを同期します。JavaScriptの配列のように、実用的な目的で使用することができます。ただし、Array.isArray()メソッドはまだfalseを返します。
例えば、以下のQMLで定義された関数は、配列とオブジェクトの2つの引数を受け取り、配列とオブジェクトの項目へのアクセスに関する標準的なJavaScriptの構文を使って、それらの内容を表示します。以下の C++ コードはこの関数を呼び出し、QVariantList とQVariantMap を渡しますが、それぞれ自動的に JavaScript の配列のような値とオブジェクトの値に変換されます:
QML | // MyItem.qml Item { function readValues(anArray, anObject) { for (var i=0; i<anArray.length; i++) console.log("Array item:", anArray[i]) for (var prop in anObject) { console.log("Object item:", prop, "=", anObject[prop]) } } } |
C++ | // C++ QQuickView view(QUrl::fromLocalFile("MyItem.qml")); QVariantList list; list << 10 << QColor(Qt::green) << "bottles"; QVariantMap map; map.insert("language", "QML"); map.insert("released", QDate(2010, 9, 21)); QMetaObject::invokeMethod(view.rootObject(), "readValues", Q_ARG(QVariant, QVariant::fromValue(list)), Q_ARG(QVariant, QVariant::fromValue(map))); |
のような出力が得られます:
Array item: 10 Array item: #00ff00 Array item: bottles Object item: language = QML Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)
同様に、C++の型がプロパティ型やメソッドのパラメータにQVariantList やQVariantMap 型を使用している場合、その値はJavaScriptの配列やオブジェクトとしてQMLで作成することができ、C++に渡される際には自動的にQVariantList やQVariantMap に変換されます。
Qt 6.5以降では、C++型のQVariantList プロパティをQMLのコードで変更することができます。ただし、C++型のQVariantMap プロパティは変更できません。これらのプロパティは値として保存され、QMLのコードで変更することはできません。マップ全体を置き換えることはできますが、その内容を操作することはできません。次のコードはm
プロパティがQVariantMap の場合には動作しません:
MyMapExposingItem { m: ({ one: 1 }) Component.onCompleted: m.ten = 10 }
次のコードは動作します:
MyMapExposingItem { m: ({ one: 1 }) Component.onCompleted: m = { one: 1, ten: 10 } }
QDateTimeからJavaScriptのDateへ
QML エンジンは、QDateTime の値と JavaScriptDate
オブジェクトとの自動型変換機能を提供します。
例えば、以下のQMLで定義された関数は、JavaScriptのDate
オブジェクトを受け取り、また、現在の日付と時刻を持つ新しいDate
オブジェクトを返します。以下の C++ コードはこの関数を呼び出し、QDateTime の値を渡します。 の値は、readDate()
関数に渡されるときに、エンジンによって自動的にDate
オブジェクトに変換されます。一方、readDate()関数は、Date
オブジェクトを返します。このオブジェクトは、C++ で受け取ったときに自動的にQDateTime 値に変換されます:
QML | // MyItem.qml Item { function readDate(dt) { console.log("The given date is:", dt.toUTCString()); return new Date(); } } |
C++ | // C++QQuickViewビュー(QUrl::fromLocalFile("MyItem.qml"));QDateTimedateTime=QDateTime::currentDateTime();QDateTimeretValue;QMetaObject::invokeMethod(view.rootObject(), "readDate",Q_RETURN_ARG(QVariantret値),Q_ARG(QVariant,QVariant::fromValue(dateTime))); qDebug() << "Value returned from readDate():" << retValue; |
同様に、C++の型がプロパティの型やメソッドのパラメータにQDateTime を使用している場合、その値はJavaScriptのDate
オブジェクトとしてQMLで作成することができ、C++に渡される際に自動的にQDateTime の値に変換されます。
注意: 月番号の違いに注意してください:JavaScriptでは1月を0から11までとし、Qtでは1月を1から12までとします。
注意: JavaScriptで文字列をDate
オブジェクトの値として使用する場合、時間フィールドを持たない文字列(つまり単純な日付)は、関連する日のUTC開始時刻として解釈されることに注意してください。new Date(y, m, d)
ではその日のローカル時刻の開始時刻が使用されます。JavaScriptでDate
オブジェクトを作成する他のほとんどの方法は、名前にUTCを含むメソッドを使用しない限り、ローカル時刻を生成します。getHours()
あなたのプログラムがUTCより後ろのゾーン(公称では本初子午線より西)で実行される場合、日付のみの文字列を使用すると、Date
オブジェクトが生成され、getDate()
は文字列の日数より1つ少なくなります。これらのメソッドのUTCバリアントであるgetUTCDate()
とgetUTCHours()
は、そのようなDate
オブジェクトに対して期待する結果を与えます。次のセクションも参照してください。
QDate と JavaScript Date
QMLエンジンは、QDate とJavaScriptのDate
の間で、日付をUTCの開始日で表現することにより、自動的に変換します。日付はQDateTime を経由してdate() メソッドを選択することでQDate にマップされ、UTC形式が次の日の始まりと重ならない限り、ローカルタイム形式が使われます。
この少々風変わりな配置は、JavaScriptが日付のみの文字列からDate
オブジェクトを構築する場合、その日のUTC開始時刻を使用しますが、new Date(y, m, d)
では、前のセクションの最後の注釈で説明したように、指示された日付のローカルタイム開始時刻を使用するという事実を回避するためのものです。
その結果、QDate のプロパティやパラメータがQMLに公開されている場合、その値を読み取る際には注意が必要です。Date.getUTCFullYear()
、Date.getUTCMonth()
、Date.getUTCDate()
のメソッドは、その名前にUTCが含まれていない対応するメソッドよりも、ユーザーが期待する結果を提供する可能性が高くなります。
そのため、QDateTime プロパティを使用する方がより堅牢であることが一般的です。これにより、QDateTime 側で、日付(と時刻)が UTC で指定されているか、ローカルタイムで指定されているかを制御することができます。JavaScript コードが同じ基準で動作するように書かれている限り、トラブルを避けることができるはずです。
QTimeとJavaScriptの日付
QMLエンジンは、QTime の値からJavaScriptのDate
オブジェクトへの自動型変換を提供します。QTime の値には日付の要素が含まれていないため、変換のためにのみ生成されます。従って、結果の Date オブジェクトの日付成分に依存してはいけません。
JavaScriptのDate
オブジェクトからQTime への変換は、QDateTime オブジェクト(ローカル時間を使用)に変換し、そのtime ()メソッドを呼び出すことで行われます。
シーケンス型からJavaScriptの配列へ
シーケンス型の一般的な説明についてはQML シーケンス型を参照してください。QtQml module には使いたいシーケンス型がいくつか含まれています。
また、QJSEngine::newArray() を使ってQJSValue を構築することで、リストのようなデータ構造を作ることもできます。このようなJavaScriptの配列は、QMLとC++の間で受け渡しする際に変換を必要としません。C++ から JavaScript 配列を操作する方法についてはQJSValue#Working With Arrays を参照してください。
QByteArray から JavaScript ArrayBuffer への変換
QML エンジンはQByteArray の値と JavaScriptArrayBuffer
オブジェクトとの自動型変換機能を提供します。
値の型
QPoint のような Qt のいくつかの値型は、JavaScript では C++ API と同じプロパティや関数を持つオブジェクトとして表現されます。C++ のカスタム値型でも同じ表現が可能です。QMLエンジンでカスタム値型を有効にするには、クラス宣言にQ_GADGET
のアノテーションを付ける必要があります。JavaScriptの表現で表示されるプロパティは、Q_PROPERTY
で宣言する必要があります。同様に、関数はQ_INVOKABLE
でマークする必要があります。これはQObject ベースの C++ API でも同じです。例えば、以下のActor
クラスはガジェットとしてアノテーションされ、プロパティを持っています:
class Actor { Q_GADGET Q_PROPERTY(QString name READ name WRITE setName) public: QString name() const { return m_name; } void setName(const QString &name) { m_name = name; } private: QString m_name; }; Q_DECLARE_METATYPE(Actor)
通常のパターンは、プロパティの型としてガジェットクラスを使用するか、シグナルの引数としてガジェットを発することです。このような場合、ガジェットのインスタンスはC++とQMLの間で値として渡されます(値型であるため)。QMLのコードがガジェットのプロパティを変更した場合、ガジェット全体が再作成され、C++のプロパティ・セッターに引き渡されます。Qt 5では、ガジェット型をQMLで直接宣言してインスタンス化することはできません。対照的に、QObject インスタンスは宣言することができます。QObject インスタンスは常に C++ から QML へポインタによって渡されます。
列挙型
カスタムの列挙型をデータ型として使用するには、そのクラスを登録し、さらに Qt のメタオブジェクトシステムに登録するために列挙型をQ_ENUM() で宣言する必要があります。例えば、以下のMessage
クラスはStatus
列挙型を持っています:
class Message : public QObject { Q_OBJECT Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: enum Status { Ready, Loading, Error }; Q_ENUM(Status) Status status() const; signals: void statusChanged(); };
Message
クラスが QML の型システムに登録されていれば、Status
enum を QML から利用することができます:
Message { onStatusChanged: { if (status == Message.Ready) console.log("Message is loaded!") } }
注意: QMLからアクセスするためには、enumの値の名前は大文字で始まらなけれ ばなりません。
... enum class Status { Ready, Loading, Error } Q_ENUM(Status) ...
enumクラスはスコープされたプロパティとスコープされていないプロパティとしてQMLに登録されます。Ready
の値はMessage.Status.Ready
とMessage.Ready
に登録されます。
enum クラスを使用する場合、同じ識別子を使用する複数の enum が存在する可能性があります。スコープされていない登録は、最後に登録された列挙型で上書きされます。このような名前の衝突を含むクラスでは、特別なQ_CLASSINFO マクロでクラスに注釈を付けることで、スコープなし登録を無効にすることができます。スコープされた列挙が同じ名前空間にマージされないようにするには、RegisterEnumClassesUnscoped
という名前とfalse
という値を使用します。
class Message : public QObject { Q_OBJECT Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") Q_ENUM(ScopedEnum) Q_ENUM(OtherValue) public: enum class ScopedEnum { Value1, Value2, OtherValue }; enum class OtherValue { Value1, Value2 }; };
関連する型の列挙型は通常、関連する型のスコープに登録されます。例えば、Q_PROPERTY の宣言で異なる型の列挙型を使用すると、その型のすべての列挙型がQMLで使用できるようになります。このような現象は、機能であるというよりも、むしろ問題です。これを防ぐためには、Q_CLASSINFO という特別なマクロでクラスのアノテーションを記述してください。この型に関連する型の列挙型を登録できないようにするには、RegisterEnumsFromRelatedTypes
という名前にfalse
という値をつけます。
QMLで使用する列挙型は、他の型に注入される列挙型に依存するのではなく、QML_ELEMENT やQML_NAMED_ELEMENT を使用して、明示的に登録する必要があります。
class OtherType : public QObject { Q_OBJECT QML_ELEMENT public: enum SomeEnum { A, B, C }; Q_ENUM(SomeEnum) enum AnotherEnum { D, E, F }; Q_ENUM(AnotherEnum) }; class Message : public QObject { Q_OBJECT QML_ELEMENT // This would usually cause all enums from OtherType to be registered // as members of Message ... Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT) // ... but this way it doesn't. Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false") public: OtherType::SomeEnum someEnum() const { return OtherType::B; } };
重要な違いはQMLにおける列挙型のスコープです。関連するクラスの列挙型が自動的に登録される場合、そのスコープはインポートされた型となります。上の例では、Q_CLASSINFO がなければ、Message.A
を使うことになります。列挙型を保持するC++型が明示的に登録され、関連型からの列挙型の登録が抑制されている場合、列挙型を保持するC++型のQML型は、そのすべての列挙型のスコープとなります。QMLではMessage.A
の代わりにOtherType.A
を使うことになります。
QML_FOREIGN を使って変更できない型を登録することもできます。また、QML_FOREIGN_NAMESPACE を使用すると、同じ C++ 型が QML の値型としても登録されている場合でも、C++ 型の列挙子を任意の大文字の名前の QML 名前空間に登録することができます。
シグナルやメソッドのパラメータとしての列挙型
列挙型パラメータを持つ C++ のシグナルやメソッドは、列挙型とシグナルやメソッドが同じクラス内で宣言されているか、列挙型の値がQt Namespace で宣言されているものであれば、QML から利用することができます。
さらに、列挙型パラメータを持つ C++ シグナルをconnect()関数を使って QML の関数に接続する場合には、qRegisterMetaType() を使って列挙型を登録する必要があります。
QML のシグナルの場合、enum 型の値はint
を用いてシグナルのパラメータとして渡すことができます:
Message { signal someOtherSignal(int statusValue) Component.onCompleted: { someOtherSignal(Message.Loading) } }
© 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.