Realize the interaction between C++ and QML in Qt


Realize the interaction between C++ and QML in Qt

Qt is a powerful cross-platform application development framework that supports both C++ and QML to develop applications. Through the interaction of C++ and QML, we can realize more flexible and powerful applications. This article will introduce in detail how to create a custom object in Qt, send a signal on the QML side and bind it to the C++ side, send a signal on the C++ side and bind it to the QML side, and realize that the QML side directly calls the C++ side function and the C++ side directly. The method to call the QML side function.

1. Create a custom object

In Qt, we can use QObjectas base class to create custom objects. First, we need to define an inherited class in C++ QObjectand register it in QML so that QML can access this object. The specific steps are as follows:

  1. Create a new C++ class, eg MyObject, and inherit from QObject.
  2. MyObjectThe properties and functions that need to be accessed in QML are declared in the class and marked with Q_PROPERTYand macros.Q_INVOKABLE
  3. MyObjectAdd signals that need to be accessed in QML in the class and mark Q_SIGNALthem with macros.
  4. MyObjectAdd the corresponding slot function in the class, and handle the logic of the signal in the function implementation .
  5. In the main program of Qt, use qmlRegisterTypethe function to MyObjectregister the class into the QML engine.
// 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();
}

In the above code, we created a MyObjectcustom object named and registered it with QML. In QML, you can import MyObject 1.0introduce this custom object through a statement and use it MyObjectto create an instance.


// 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. Send a signal in QML and bind it to the C++ side

  1. To define a signal in QML, use signalthe keyword tag.
// MyItem.qml

import QtQuick 2.15

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

    // ...
}
  1. Where the signal needs to be triggered, call signalthe function marked with the keyword and pass the corresponding parameters.
// MyItem.qml

Button {
    text: "Send Signal"
    onClicked: {
        mySignal("Hello from QML")    // 点击按钮出触发信号
    }
}
  1. In C++, connect the signal in QML to the corresponding slot function to perform the corresponding operation when the signal is triggered.
// 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. In the main program of Qt, register the custom class
// 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. In QML, Connectionselements are used to bind signals to C++ slots.
// main.qml

import QtQuick 2.15

Item {
   // 信号连接
    Connections {
        target: myItem
        onMySignal: {
            myObject.handleSignal(message)
        }
    }

    MyItem {
        id: myItem
        
    }
}

In the above code, we MyItemdefine a mySignalsignal named in QML. When the button is clicked, we call mySignalthe function and pass it a parameter. In C++, we create an MyObjectobject named and main.qmlregister it in myObject. Then, in Connectionsthe element, we bind myItemthe mySignalsignal to myObjectthe handleSignalslot function so that the corresponding slot function is called when the signal is triggered.

In this way, when a signal is triggered in QML mySignal, the slot function will be called myObjectand handleSignalthe corresponding parameters will be passed to it.

This completes the process of sending signals on the QML side and binding to the C++ side

3. Send a signal on the C++ side and bind it to the QML side

In C++, we can define signals and send signals when specific events occur, and then bind these signals to functions on the QML side. The specific steps are as follows:

  1. Define the signal in a custom object in C++ and Q_SIGNALmark it with a macro.
  2. Where a signal needs to be triggered, call emitthe function marked with the keyword to send the signal.
  3. In QML, Connectionselements are used to bind C++ signals to QML functions.
// 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();
        }
    }
}

In the above code, we emit a signal called in the MyObjectobject's function . In QML, elements are used to bind signals to corresponding handlers.handleButtonClickedbuttonClickedConnectionsbuttonClicked

4. The QML side directly calls the C++ side function

In QML, we can directly call functions on the C++ side to implement more advanced functions in the logic of the application. The specific steps are as follows:

  1. Declare the functions that need to be accessed in QML in the C++ custom object, and use Q_INVOKABLEmacros to mark them.
  2. In QML, these functions are called by directly referencing the properties and functions of C++ objects.
// 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();
        }
    }
}

In the above code, we MyObjectdeclared a cppFunctionfunction called in the object which is marked as callable in QML. In QML, myObject.cppFunction()this function is called through the method.

5. The C++ side directly calls the QML side function

In C++, we can directly call the functions defined in QML to implement more advanced functions in the logic of the application. The specific steps are as follows:

  1. In QML, use QtObjectthe element to create an object for the function in the QML file, and set a to this object id.
  2. In C++, use QVariantand QMetaObjectto call functions defined in 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();
}

In the above code, we have used elements in QML QtObjectto define a qmlFunctionfunction called. In C++, we use QMetaObjectand QMetaMethodto call this function.

6 Conclusion

Through the interaction between C++ and QML, we can create custom objects, and realize the sending and binding of signals between C++ and QML. We can also directly call functions on the C++ side on the QML side, and directly call functions on the QML side on the C++ side. This interaction allows us to develop applications more flexibly and achieve more advanced functions.

I hope this article helps you understand how to realize the interaction between C++ and QML in Qt!

Guess you like

Origin blog.csdn.net/ljn1046016768/article/details/131317249