ここにディレクトリのタイトルを書きます
Qt で C++ と QML 間の対話を実現する
Qt は、C++ と QML の両方をサポートしてアプリケーションを開発する強力なクロスプラットフォーム アプリケーション開発フレームワークです。C++ と QML の相互作用を通じて、より柔軟で強力なアプリケーションを実現できます。この記事では、Qt でカスタム オブジェクトを作成する方法、QML 側でシグナルを送信して C++ 側にバインドする方法、C++ 側でシグナルを送信して QML 側にバインドする方法、および QML が側はC++側関数を直接呼び出し、C++側は直接QML側関数を呼び出すメソッドです。
1.カスタムオブジェクトを作成する
Qt では、カスタム オブジェクトを作成するための基本クラスとして使用できますQObject
。まず、C++ で継承クラスを定義しQObject
、QML がこのオブジェクトにアクセスできるように、それを QML に登録する必要があります。具体的な手順は次のとおりです。
- 新しい C++ クラス (例: ) を作成し
MyObject
、 から継承しますQObject
。 MyObject
QML でアクセスする必要があるプロパティと関数はクラスで宣言され、Q_PROPERTY
とマクロQ_INVOKABLE
でマークされます。MyObject
QML でアクセスする必要がある信号をクラスに追加し、マクロでマークしますQ_SIGNAL
。MyObject
対応するスロット関数をクラスに追加し、関数実装で信号のロジックを処理します。- Qt のメインプログラムで、
qmlRegisterType
関数を使用してMyObject
クラスを QML エンジンに登録します。
// MyObject.h
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
// 宏标记
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit MyObject(QObject *parent = nullptr);
int value() const;
void setValue(int newValue);
signals:
void valueChanged(int newValue);
public slots:
void handleButtonClicked();
};
// MyObject.cpp
#include "MyObject.h"
MyObject::MyObject(QObject *parent) : QObject(parent)
{
}
int MyObject::value() const
{
return m_value;
}
void MyObject::setValue(int newValue)
{
if (m_value != newValue) {
m_value = newValue;
emit valueChanged(m_value);
}
}
void MyObject::handleButtonClicked()
{
// 处理按钮点击逻辑
}
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "MyObject.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// 注册自定义对象到QML
qmlRegisterType<MyObject>("MyObject", 1, 0, "MyObject");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
上記のコードでは、MyObject
という名前のカスタム オブジェクトを作成し、QML に登録しました。QML では、import MyObject 1.0
ステートメントを通じてこのカスタム オブジェクトを導入し、それを使用してMyObject
インスタンスを作成できます。
// main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import MyObject 1.0 // 导入自定义类
Window {
visible: true
width: screenW
height: 480
title: qsTr("Hello World")
// 使用
MyObject {
id : myobj
console.log(myobj.value)
}
}
2. QML でシグナルを送信し、C++ 側にバインドします。
- QML でシグナルを定義するには、
signal
キーワード タグを使用します。
// MyItem.qml
import QtQuick 2.15
Item {
signal mySignal(string message) // 定义信号
// ...
}
- シグナルをトリガーする必要がある場合は、
signal
キーワードでマークされた関数を呼び出し、対応するパラメーターを渡します。
// MyItem.qml
Button {
text: "Send Signal"
onClicked: {
mySignal("Hello from QML") // 点击按钮出触发信号
}
}
- C++ では、QML の信号を対応するスロット関数に接続し、信号がトリガーされたときに対応する操作を実行します。
// MyObject.h
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr);
public slots:
void handleSignal(QString message); // 接受信号的槽函数
};
// MyObject.cpp
#include "MyObject.h"
MyObject::MyObject(QObject *parent) : QObject(parent)
{
}
void MyObject::handleSignal(QString message)
{
// 处理接收到的信号
qDebug() << "Received signal from QML:" << message;
}
- Qtのメインプログラムにカスタムクラスを登録します
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "MyObject.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyObject myObject; // 创建C++对象
// 注册自定义对象到QML
qmlRegisterType<MyObject>("MyObject", 1, 0, "MyObject");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
- QML では、
Connections
要素は信号を C++ スロットにバインドするために使用されます。
// main.qml
import QtQuick 2.15
Item {
// 信号连接
Connections {
target: myItem
onMySignal: {
myObject.handleSignal(message)
}
}
MyItem {
id: myItem
}
}
上記のコードでは、QML で名前を付けた信号MyItem
を定義します。mySignal
ボタンがクリックされると、mySignal
関数が呼び出され、パラメーターが渡されます。C++ では、MyObject
という名前のオブジェクトを作成し、main.qml
に登録しますmyObject
。次に、Connections
要素内でmyItem
信号をスロット関数mySignal
にバインドし、信号がトリガーされたときに対応するスロット関数が呼び出されるようにします。myObject
handleSignal
このようにして、 QML で信号がトリガーされるとmySignal
、スロット関数が呼び出されmyObject
、handleSignal
対応するパラメーターがそれに渡されます。
これで、QML 側でシグナルを送信し、C++ 側にバインドするプロセスが完了しました。
3. C++ 側でシグナルを送信し、QML 側にバインドします。
C++ では、シグナルを定義し、特定のイベントが発生したときにシグナルを送信し、これらのシグナルを QML 側の関数にバインドできます。具体的な手順は次のとおりです。
- C++ のカスタム オブジェクトで信号を定義し、
Q_SIGNAL
マクロでマークします。 - シグナルをトリガーする必要がある場合は、
emit
キーワードでマークされた関数を呼び出してシグナルを送信します。 - QML では、
Connections
要素は C++ 信号を QML 関数にバインドするために使用されます。
// MyObject.h
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit MyObject(QObject *parent = nullptr);
int value() const;
void setValue(int newValue);
signals:
void valueChanged(int newValue);
void buttonClicked();
public slots:
void handleButtonClicked();
};
// MyObject.cpp
#include "MyObject.h"
MyObject::MyObject(QObject *parent) : QObject(parent)
{
}
int MyObject::value() const
{
return m_value;
}
void MyObject::setValue(int newValue)
{
if (m_value != newValue) {
m_value = newValue;
emit valueChanged(m_value);
}
}
void MyObject::handleButtonClicked()
{
// 发送信号
emit buttonClicked();
}
// main.qml
import
QtQuick 2.15
import com.example 1.0
Item {
width: 400
height: 300
// 信号连接
Connections {
target: myObject
onButtonClicked: {
console.log("Button clicked");
}
}
MyObject {
id: myObject
onValueChanged: {
console.log("New value:", newValue);
}
}
Button {
text: "Click me"
onClicked: {
myObject.handleButtonClicked();
}
}
}
上記のコードでは、MyObject
オブジェクトのfunctionhandleButtonClicked
で呼び出されるシグナルを発行しますbuttonClicked
。QML では、要素はシグナルを対応するハンドラーにバインドするConnections
ために使用されます。buttonClicked
4. QML側がC++側関数を直接呼び出す
QML では、C++ 側で関数を直接呼び出して、アプリケーションのロジックでより高度な関数を実装できます。具体的な手順は次のとおりです。
- C++ カスタム オブジェクトの QML でアクセスする必要がある関数を宣言し、
Q_INVOKABLE
マクロを使用してそれらをマークします。 - QML では、これらの関数は C++ オブジェクトのプロパティと関数を直接参照することによって呼び出されます。
// MyObject.h
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit MyObject(QObject *parent = nullptr);
int value() const;
void setValue(int newValue);
Q_INVOKABLE void cppFunction();
signals:
void valueChanged(int newValue);
public slots:
void handleButtonClicked();
};
// main.qml
import QtQuick 2.15
import com.example 1.0
Item {
width: 400
height: 300
MyObject {
id: myObject
onValueChanged: {
console.log("New value:", newValue);
}
}
Button {
text: "Click me"
onClicked: {
myObject.handleButtonClicked();
myObject.cppFunction();
}
}
}
上記のコードでは、QML で呼び出し可能としてマークされているオブジェクト内で呼び出される関数をMyObject
宣言しました。cppFunction
QML では、myObject.cppFunction()
この関数はメソッドを通じて呼び出されます。
5. C++側がQML側関数を直接呼び出す
C++ では、QML で定義された関数を直接呼び出して、アプリケーションのロジックでより高度な関数を実装できます。具体的な手順は次のとおりです。
- QML では、
QtObject
要素を使用して QML ファイル内に関数のオブジェクトを作成し、 をこのオブジェクトに設定しますid
。 - C++ では、
QVariant
と を使用してQMetaObject
QML で定義された関数を呼び出します。
// main.qml
import QtQuick 2.15
QtObject {
id: qmlFunctions
function qmlFunction() {
console.log("QML function called");
}
}
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QMetaObject>
#include <QMetaMethod>
int main(int argc, char *argv[])
{
Q
GuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
// 调用QML中的函数
QObject* rootObject = engine.rootObjects().first();
QObject* qmlFunctions = rootObject->findChild<QObject*>("qmlFunctions");
if (qmlFunctions) {
const QMetaObject* metaObject = qmlFunctions->metaObject();
int index = metaObject->indexOfMethod("qmlFunction()");
if (index != -1) {
QMetaMethod method = metaObject->method(index);
method.invoke(qmlFunctions);
}
}
return app.exec();
}
上記のコードでは、QML の要素を使用して、呼び出される関数QtObject
を定義しましたqmlFunction
。C++ では、この関数を呼び出すためにQMetaObject
と を使用します。QMetaMethod
6 結論
C++ と QML 間の対話を通じて、カスタム オブジェクトを作成し、C++ と QML 間のシグナルの送信とバインディングを実現できます。C++ 側の関数を QML 側で直接呼び出したり、QML 側の関数を C++ 側で直接呼び出したりすることもできます。この相互作用により、アプリケーションをより柔軟に開発し、より高度な機能を実現することができます。
この記事が、Qt で C++ と QML の間の対話を実現する方法を理解するのに役立つことを願っています。