C++ から QML オブジェクトとのやり取り
すべてのQMLオブジェクト型は、エンジンによって内部的に実装されているか、サードパーティのソースによって定義されているかを問わず、QObject から派生した型です。つまり、QMLエンジンはQtメタオブジェクトシステムを使用して、任意のQMLオブジェクト型を動的にインスタンス化し、作成されたオブジェクトを検査することができます。
これは、視覚的にレンダリング可能なQMLオブジェクトを表示する場合でも、非視覚的なQMLオブジェクトのデータをC++アプリケーションに統合する場合でも、C++コードからQMLオブジェクトを作成する際に役立ちます。QMLオブジェクトが作成されると、C++側からそのオブジェクトを検査して、プロパティの読み書き、メソッドの呼び出し、シグナル通知の受信を行うことができます。
C++ およびさまざまな QML 統合方法の詳細については、「C++ と QML の統合の概要」ページを参照してください。
C++ からの QML オブジェクトの読み込み
QMLドキュメントは、QQmlComponent またはQQuickView を使用して読み込むことができます。QQmlComponent は、QMLドキュメントをC++オブジェクトとして読み込み、その後C++コードからそのオブジェクトを変更できるようにします。QQuickView も同様の動作をしますが、QQuickView はQWindow を継承したクラスであるため、読み込まれたオブジェクトは視覚的な表示としてもレンダリングされます。QQuickView は、一般的に、表示可能なQMLオブジェクトをアプリケーションのユーザーインターフェースに統合するために使用されます。
たとえば、次のようなMyItem.qml ファイルがあるとします:
import QtQuick
Item {
width: 100; height: 100
}このQMLドキュメントは、以下のC++コードを使用してQQmlComponent またはQQuickView で読み込むことができます。QQmlComponent を使用する場合は、QQmlComponent::create()を呼び出してコンポーネントの新しいインスタンスを作成する必要がありますが、QQuickView ではコンポーネントのインスタンスが自動的に作成され、QQuickView::rootObject()を介してアクセスできます:
| |
この `object ` は、作成された `MyItem.qml ` コンポーネントのインスタンスです。これで、QObject::setProperty() またはQQmlProperty::write() を使用して、項目のプロパティを変更できるようになります:
object->setProperty("width", 500);
QQmlProperty(object, "width").write(500);QObject::setProperty() とQQmlProperty::write() の違いは、後者ではプロパティ値を設定するだけでなく、バインディングも解除される点にあります。例えば、上記のwidth による代入が、height へのバインディングであったと仮定すると:
width: heightobject->setProperty("width", 500) の呼び出し後に、Item のheight が変更された場合、バインディングは有効なままであるため、width は再度更新されます。しかし、QQmlProperty(object, "width").write(500) の呼び出し後にheight が変更された場合、バインディングはもはや存在しないため、width は変更されません。
あるいは、オブジェクトを実際の型にキャストして、コンパイル時の安全性を確保しながらメソッドを呼び出すこともできます。この場合、MyItem.qml の基底オブジェクトはItem であり、これはQQuickItem クラスによって定義されています:
QQuickItem *item = qobject_cast<QQuickItem*>(object);
item->setWidth(500);また、QMetaObject::invokeMethod() およびQObject::connect() を使用して、コンポーネントで定義されたシグナルへの接続やメソッドの呼び出しを行うこともできます。詳細については、以下の「QML メソッドの呼び出しと QML シグナルへの接続」を参照してください。
明確に定義された C++ インターフェースを介した QML オブジェクトへのアクセス
C++ から QML とやり取りする最良の方法は、C++ 側でそのためのインターフェースを定義し、QML 側でそれにアクセスすることです。 他の方法では、QML コードをリファクタリングしただけで、QML と C++ の連携が容易に破綻してしまう可能性があります。また、QML 経由で制御を行うことで、ユーザーや qmllint などのツール双方にとって、QML と C++ コードの相互作用を把握しやすくなるため、その理解にも役立ちます。 C++からQMLにアクセスする場合、外部のC++コードが特定のQMLコンポーネントを変更していないことを手動で確認しなければ、そのQMLコードを理解できなくなります。また、たとえ確認できたとしても、アクセスの範囲は時間の経過とともに変化する可能性があるため、この戦略を継続して使用することはメンテナンス上の負担となります。
QMLに連携を制御させるには、まずC++インターフェースを定義する必要があります:
class CppInterface : public QObject
{
Q_OBJECT
QML_ELEMENT
// ...
};QML主導のアプローチでは、このインターフェースに対して2つの方法で操作を行うことができます:
シングルトン
1つの方法は、インターフェースにQML_SINGLETONマクロを追加してシングルトンとして登録し、すべてのコンポーネントから利用できるようにすることです。これにより、簡単なインポート文を通じてそのインターフェースを利用できるようになります:
import my.company.module
Item {
Component.onCompleted: {
CppInterface.foo();
}
}このアプローチは、ルートコンポーネント以外の場所でもインターフェースが必要になる場合に使用します。単にオブジェクトを継承させるだけでは、プロパティを介して他のコンポーネントに明示的に渡すか、非推奨かつ処理速度の遅い無修飾アクセスを用いる必要が生じるためです。
初期プロパティ
別の方法として、QML_UNCREATABLE を使用してインターフェースを「生成不可」としてマークし、QQmlComponent::createWithInitialProperties() および QML 側の必須プロパティを使用して、それをルート QML コンポーネントに渡す方法があります。
ルートコンポーネントは、次のような形になるでしょう:
import QtQuick
Item {
required property CppInterface interface
Component.onCompleted: {
interface.foo();
}
}ここでプロパティを必須として指定することで、インターフェースプロパティが設定されていない状態でコンポーネントが作成されるのを防ぐことができます。
その後、『C++からQMLオブジェクトを読み込む』で説明されているのと同じ方法で、createWithInitialProperties() を使用する以外は、コンポーネントを初期化できます:
component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});この方法は、インターフェースがルートコンポーネントからのみ利用されればよいことが分かっている場合に推奨されます。また、C++ 側でインターフェースのシグナルやスロットに接続しやすくなります。
これらの方法のいずれもニーズに合わない場合は、代わりにC++モデルの使用を検討することをお勧めします。
オブジェクト名によるロード済みQMLオブジェクトへのアクセス
QMLコンポーネントは、本質的に、兄弟要素や子要素を持つ子要素からなるオブジェクトツリーです。QMLコンポーネントの子オブジェクトは、`QObject::objectName `プロパティと`QObject::findChild()`を使用して特定できます。たとえば、MyItem.qml のルートアイテムにRectangle という子アイテムがある場合:
import QtQuick
Item {
width: 100; height: 100
Rectangle {
anchors.fill: parent
objectName: "rect"
}
}その子要素は次のように特定できます:
なお、1つのオブジェクトが、同じobjectName を持つ複数の子を持つ場合があることに注意してください。たとえば、ListView はデリゲートのインスタンスを複数生成するため、そのデリゲートが特定のobjectNameで宣言されている場合、ListView には同じobjectName を持つ複数の子が存在することになります。この場合、QObject::findChildren()を使用することで、一致するobjectName を持つすべての子を検索できます。
警告: C++ から QML オブジェクトにアクセスして操作することは可能ですが 、テストやプロトタイピングの目的を除き、このアプローチは推奨されません。 QMLとC++の統合の強みの1つは、C++のロジックやデータセットのバックエンドとは独立してQMLでUIを実装できる点ですが、C++側からQMLを直接操作し始めると、この利点は失われてしまいます。また、このようなアプローチでは、対応するC++コードに影響を与えずにQMLのUIを変更することが困難になります。
C++ から QML オブジェクト型のメンバにアクセスする
プロパティ
QML オブジェクトで宣言されたプロパティは、C++ から自動的にアクセス可能です。次のような QML アイテムがあるとします:
someNumber プロパティの値は、QQmlProperty 、あるいはQObject::setProperty()およびQObject::property()を使用して設定および取得できます:
QQmlEngine engine;
QQmlComponent component(&engine, "MyItem.qml");
QObject*object =component.create();
qDebug() << "Property value:" << QQmlProperty::read(object, "someNumber").toInt();
QQmlProperty::write(object, "someNumber", 5000);
qDebug() << "Property value:" << object->property("someNumber").toInt();
object->setProperty("someNumber", 100);QMLプロパティの値を変更する際は、常にQObject::setProperty()、QQmlProperty 、またはQMetaProperty::write() を使用し、QMLエンジンにプロパティの変更が確実に通知されるようにする必要があります。例えば、カスタム型PushButton があり、そのbuttonText プロパティが内部的にm_buttonText というメンバ変数の値を反映しているとします。このようにメンバ変数を直接変更するのは推奨されません:
//bad code
QQmlComponent component(engine, "MyButton.qml");
PushButton *button = qobject_cast<PushButton*>(component.create());
button->m_buttonText = "Click me";値が直接変更されるため、Qtのメタオブジェクトシステムがバイパスされ、QMLエンジンはプロパティの変更を認識できません。つまり、buttonText へのプロパティバインディングは更新されず、onButtonTextChanged ハンドラも呼び出されません。
QMLメソッドの呼び出し
すべてのQMLメソッドはメタオブジェクトシステムに公開されており、C++からQMetaObject::invokeMethod() を使用して呼び出すことができます。 以下のコードスニペットに示すように、コロン(:)の後にパラメータおよび戻り値の型を指定できます。これは、例えば、C++ 内の特定のシグネチャを持つシグナルを、QML で定義されたメソッドに接続したい場合などに役立ちます。型を省略した場合、C++ のシグネチャでは `QVariant` が使用されます。
以下は、QMetaObject::invokeMethod() を使用して QML メソッドを呼び出す C++ アプリケーションの例です。
| QML | |
| C++ | |
コロン(:)の後に指定されるパラメータ型と戻り値型に注意してください。型名として値型やオブジェクト型を使用できます。
QMLで型が省略されているか、var として指定されている場合、QMetaObject::invokeMethod を呼び出す際には、Q_RETURN_ARG()およびQ_ARG()に対して、型としてQVariant を渡す必要があります。
QMLシグナルへの接続
すべてのQMLシグナルはC++から自動的に利用可能であり、通常のQt C++シグナルと同様にQObject::connect()を使用して接続できます。逆に、C++のシグナルは、シグナルハンドラを使用してQMLオブジェクトで受信することができます。
以下は、文字列型のパラメータを伴って発火されるqmlSignal という名前のシグナルを持つQMLコンポーネントです。このシグナルは、QObject::connect()を使用してC++オブジェクトのスロットに接続されており、qmlSignal が発火されるたびにcppSlot() メソッドが呼び出されるようになっています:
|
シグナルパラメータ内の QML オブジェクト型は、C++ におけるそのクラスへのポインタに変換されます:
|
© 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.