Qt で C++ と QML 間の対話を実現する


Qt で C++ と QML 間の対話を実現する

Qt は、C++ と QML の両方をサポートしてアプリケーションを開発する強力なクロスプラットフォーム アプリケーション開発フレームワークです。C++ と QML の相互作用を通じて、より柔軟で強力なアプリケーションを実現できます。この記事では、Qt でカスタム オブジェクトを作成する方法、QML 側でシグナルを送信して C++ 側にバインドする方法、C++ 側でシグナルを送信して QML 側にバインドする方法、および QML が側はC++側関数を直接呼び出し、C++側は直接QML側関数を呼び出すメソッドです。

1.カスタムオブジェクトを作成する

Qt では、カスタム オブジェクトを作成するための基本クラスとして使用できますQObjectまず、C++ で継承クラスを定義しQObject、QML がこのオブジェクトにアクセスできるように、それを QML に登録する必要があります。具体的な手順は次のとおりです。

  1. 新しい C++ クラス (例: ) を作成しMyObject、 から継承しますQObject
  2. MyObjectQML でアクセスする必要があるプロパティと関数はクラスで宣言され、Q_PROPERTYとマクロQ_INVOKABLEでマークされます。
  3. MyObjectQML でアクセスする必要がある信号をクラスに追加し、マクロでマークしますQ_SIGNAL
  4. MyObject対応するスロット関数をクラスに追加し、関数実装で信号のロジックを処理します
  5. 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++ 側にバインドします。

  1. QML でシグナルを定義するには、signalキーワード タグを使用します。
// MyItem.qml

import QtQuick 2.15

Item {
    signal mySignal(string message)   // 定义信号

    // ...
}
  1. シグナルをトリガーする必要がある場合は、signalキーワードでマークされた関数を呼び出し、対応するパラメーターを渡します。
// MyItem.qml

Button {
    text: "Send Signal"
    onClicked: {
        mySignal("Hello from QML")    // 点击按钮出触发信号
    }
}
  1. 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;
}
  1. 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();
}
  1. 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にバインドし、信号がトリガーされたときに対応するスロット関数が呼び出されるようにします。myObjecthandleSignal

このようにして、 QML で信号がトリガーされるとmySignal、スロット関数が呼び出されmyObjecthandleSignal対応するパラメーターがそれに渡されます。

これで、QML 側でシグナルを送信し、C++ 側にバインドするプロセスが完了しました。

3. C++ 側でシグナルを送信し、QML 側にバインドします。

C++ では、シグナルを定義し、特定のイベントが発生したときにシグナルを送信し、これらのシグナルを QML 側の関数にバインドできます。具体的な手順は次のとおりです。

  1. C++ のカスタム オブジェクトで信号を定義し、Q_SIGNALマクロでマークします。
  2. シグナルをトリガーする必要がある場合は、emitキーワードでマークされた関数を呼び出してシグナルを送信します。
  3. 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で呼び出されるシグナルを発行しますbuttonClickedQML では、要素はシグナルを対応するハンドラーにバインドするConnectionsために使用されます。buttonClicked

4. QML側がC++側関数を直接呼び出す

QML では、C++ 側で関数を直接呼び出して、アプリケーションのロジックでより高度な関数を実装できます。具体的な手順は次のとおりです。

  1. C++ カスタム オブジェクトの QML でアクセスする必要がある関数を宣言し、Q_INVOKABLEマクロを使用してそれらをマークします。
  2. 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宣言しました。cppFunctionQML では、myObject.cppFunction()この関数はメソッドを通じて呼び出されます。

5. C++側がQML側関数を直接呼び出す

C++ では、QML で定義された関数を直接呼び出して、アプリケーションのロジックでより高度な関数を実装できます。具体的な手順は次のとおりです。

  1. QML では、QtObject要素を使用して QML ファイル内に関数のオブジェクトを作成し、 をこのオブジェクトに設定しますid
  2. C++ では、QVariantと を使用してQMetaObjectQML で定義された関数を呼び出します。
// 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を定義しましたqmlFunctionC++ では、この関数を呼び出すためにQMetaObjectと を使用します。QMetaMethod

6 結論

C++ と QML 間の対話を通じて、カスタム オブジェクトを作成し、C++ と QML 間のシグナルの送信とバインディングを実現できます。C++ 側の関数を QML 側で直接呼び出したり、QML 側の関数を C++ 側で直接呼び出したりすることもできます。この相互作用により、アプリケーションをより柔軟に開発し、より高度な機能を実現することができます。

この記事が、Qt で C++ と QML の間の対話を実現する方法を理解するのに役立つことを願っています。

おすすめ

転載: blog.csdn.net/ljn1046016768/article/details/131317249