QMLとC++間のデータ型の変換
QMLとC++の間でデータ値がやり取りされる際、QMLエンジンによって、QMLまたはC++での使用に適した正しいデータ型に変換されます。そのため、やり取りされるデータは、エンジンが認識可能な型である必要があります。
Qt 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 | bool |
| unsigned 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 |
注: Qt GUIQColor 、QFont 、QQuaternion 、QMatrix4x4 などのクラスは、 Qt Quick モジュールがインクルードされている場合にのみ利用可能です。
利便性のため、これらの型の多くは、QML内で文字列値、あるいはQtQml::Qt オブジェクトが提供する関連メソッドを用いて指定することができます。例えば、Image::sourceSize プロパティはsize 型(これは自動的にQSize 型に変換されます)であり、「widthxheight」という形式の文字列値、またはQtのsize() 関数を用いて指定できます:
詳細については、「QML 値型」の各型に関するドキュメントを参照してください。
QObject 派生型
QObject から派生したクラスは、QML型システムに登録されていれば、QMLとC++間のデータ交換用の型として使用できます。
エンジンでは、インスタンス化可能な型とインスタンス化不可能な型の両方の登録が可能です。クラスが QML 型として登録されると、QML と C++ 間のデータ交換用のデータ型として使用できるようになります。型の登録に関する詳細については、「QML 型システムへの C++ 型の登録」を参照してください。
Qt と JavaScript 型の間の変換
Qt Qmlエンジンには、Qt QmlとC++間でデータを転送する際、多数のQt型を関連するJavaScript型へ、またその逆も変換するための機能が組み込まれています。これにより、データ値やその属性へのアクセスを提供するカスタム型を実装することなく、これらの型をC++やJavaScriptで使用したり、受け取ったりすることが可能になります。
(QML内のJavaScript環境では、String 、Date 、Number などのネイティブJavaScriptオブジェクトのプロトタイプを変更し、追加機能を提供しています。詳細については、「JavaScriptホスト環境」を参照してください。)
QVariantList および QVariantMap を JavaScript の配列およびオブジェクトに変換
QML エンジンは、QVariantList と JavaScript の配列類似型の間、およびQVariantMap と JavaScript オブジェクトの間で、自動的な型変換を提供します。
ECMAScriptの用語でいう「配列風」とは、配列のように使用されるオブジェクトのことです。QVariantList (およびその他のC++のシーケンシャルコンテナ)からの変換によって生成される配列風オブジェクトは、単に配列のように振る舞うだけでなく、一般的な配列メソッドも提供し、lengthプロパティを自動的に同期させます。これらは、実用上のあらゆる目的において、JavaScriptの配列とまったく同じように使用できます。 ただし、Array.isArray()メソッドは、これらに対しては依然として false を返します。
たとえば、以下のQMLで定義された関数は、配列とオブジェクトの2つの引数を期待し、配列およびオブジェクトの要素へのアクセスに標準的なJavaScript構文を使用してその内容を出力します。以下のC++コードは、この関数を呼び出し、QVariantList とQVariantMap を渡します。これらはそれぞれ、自動的にJavaScriptの配列のような値とオブジェクトの値に変換されます:
| QML | |
| C++ | |
これにより、次のような出力が得られます:
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 型を使用している場合、その値はQML内でJavaScriptの配列またはオブジェクトとして作成され、C++に渡される際に自動的にQVariantList またはQVariantMap に変換されます。
Qt 6.5 以降、C++ 型のQVariantList プロパティは、QML コードからその場で変更できるようになりました。Qt 6.9 以降、C++ 型のQVariantMap プロパティも、QML コードからその場で変更できるようになりました。
QDateTime から JavaScript の Date への変換
QMLエンジンは、QDateTime の値とJavaScriptのDate オブジェクト間の自動型変換を提供します。
たとえば、以下のQMLで定義された関数は、JavaScriptのDate オブジェクトを引数として受け取り、現在の日付と時刻を含む新しいDate オブジェクトを返します。 以下のC++コードは、この関数を呼び出し、QDateTime 値を引数として渡します。この値は、readDate() 関数に渡される際に、エンジンによって自動的にDate オブジェクトに変換されます。一方、readDate()関数はDate オブジェクトを返し、これがC++側で受け取られる際に自動的にQDateTime 値に変換されます:
| QML | |
| C++ | |
同様に、C++の型がプロパティの型やメソッドのパラメータとしてQDateTime を使用している場合、その値はQML内でJavaScriptのDate オブジェクトとして生成され、C++に渡されると自動的にQDateTime の値に変換されます。
注: 月の番号付けの違いに注意してください 。JavaScriptでは1月を0、12月を11と数えますが、Qtでは1月を1、12月を12と数えるため、1つずれています。
注: JavaScript の文字列を `Date ` オブジェクトの値として使用する場合 、時間フィールドを含まない文字列(つまり単純な日付)は、その日の UTC 開始時刻として解釈されることに注意してください。これに対し、`new Date(y, m, d) ` はその日の現地時間の開始時刻を使用します。 JavaScriptでDate オブジェクトを構築する他のほとんどの方法では、名前に「UTC」を含むメソッドを使用しない限り、ローカル時間が生成されます。 プログラムが UTC より遅れているタイムゾーン(名目上は本初子午線の西側)で実行される場合、日付のみの文字列を使用すると、Date オブジェクトが生成され、そのgetDate() は文字列の日付番号より 1 少なくなります。また、通常、getHours() の値は大きくなります。 これらのメソッドのUTC版であるgetUTCDate() およびgetUTCHours() を使用すると、そのようなDate オブジェクトに対して期待通りの結果が得られます。次のセクションも参照してください。
QDate と JavaScript の Date
QMLエンジンは、日付をその日のUTC開始時刻として表現することで、QDate とJavaScriptのDate 型との間を自動的に変換します。日付は、QDateTime を介してQDate にマッピングされ、そのdate()メソッドが選択されます。この際、日付のローカルタイム形式が使用されますが、UTC形式が翌日の開始時刻と一致する場合は、UTC形式が使用されます。
この少し風変わりな仕組みは、前のセクションの末尾の注記で説明したように、JavaScriptが日付のみの文字列からDate オブジェクトを生成する際には1日のUTC開始時刻を使用するのに対し、new Date(y, m, d) は指定された日付の現地時間の開始時刻を使用するという事実に対する回避策である。
その結果、QDate のプロパティやパラメータがQMLに公開されている場合、その値を読み取る際には注意が必要です。Date.getUTCFullYear() 、Date.getUTCMonth() 、およびDate.getUTCDate() メソッドは、名前にUTCが含まれていない対応するメソッドよりも、ユーザーが期待する結果を返す可能性が高いです。
したがって、一般にQDateTime プロパティを使用する方が堅牢です。これにより、QDateTime 側で、日付(および時刻)がUTCかローカルタイムのどちらで指定されるかを制御できるようになります。JavaScriptコードが同じ標準に従って記述されていれば、問題を回避できるはずです。
QTime と JavaScript の Date
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 の値とJavaScriptのArrayBuffer オブジェクト間の自動型変換を提供します。
値の型
QPoint などの Qt XML の一部の値型は、C++ API と同様のプロパティや関数を持つオブジェクトとして JavaScript で表現されます。カスタム C++ 値型についても、同様の表現が可能です。 QMLエンジンでカスタム値型を有効にするには、クラス宣言にQ_GADGET を付与する必要があります。JavaScript表現で公開するプロパティは、Q_PROPERTY で宣言する必要があります。同様に、関数にはQ_INVOKABLE を付与する必要があります。これは、QObject ベースのC++ APIと同様です。たとえば、以下のActor クラスはgadgetとしてアノテーションされ、以下のプロパティを持っています:
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 列挙型をQMLから使用できます:
Message {
onStatusChanged: {
if (status == Message.Ready)
console.log("Message is loaded!")
}
}QMLで列挙型をflags 型として使用するには、Q_FLAG() を参照してください。
注: QML からアクセスできるようにするには、列挙値の名前 は大文字で始まる必要があります。
...
enum class Status {
Ready,
Loading,
Error
}
Q_ENUM(Status)
...列挙型クラスは、QML においてスコープ付きおよびスコープなしのプロパティとして登録されます。Ready の値は、Message.Status.Ready およびMessage.Ready として登録されます。
列挙型クラスを使用する場合、同じ識別子を持つ複数の列挙型が存在することがあります。 スコープ外での登録は、最後に登録された列挙型によって上書きされます。このような名前の競合を含むクラスについては、特別な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 から使用できます。
さらに、enum パラメータを持つ C++ シグナルをconnect()関数を使用して QML 関数に接続する場合、その enum 型をqRegisterMetaType() を使用して登録する必要があります。
QMLシグナルの場合、int 型を使用して、列挙型値をシグナルパラメータとして渡すことができます:
Message {
signal someOtherSignal(int statusValue)
Component.onCompleted: {
someOtherSignal(Message.Loading)
}
}© 2026 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.