Write directory title here
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 QObject
as base class to create custom objects. First, we need to define an inherited class in C++ QObject
and register it in QML so that QML can access this object. The specific steps are as follows:
- Create a new C++ class, eg
MyObject
, and inherit fromQObject
. MyObject
The properties and functions that need to be accessed in QML are declared in the class and marked withQ_PROPERTY
and macros.Q_INVOKABLE
MyObject
Add signals that need to be accessed in QML in the class and markQ_SIGNAL
them with macros.MyObject
Add the corresponding slot function in the class, and handle the logic of the signal in the function implementation .- In the main program of Qt, use
qmlRegisterType
the function toMyObject
register 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 MyObject
custom object named and registered it with QML. In QML, you can import MyObject 1.0
introduce this custom object through a statement and use it MyObject
to 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
- To define a signal in QML, use
signal
the keyword tag.
// MyItem.qml
import QtQuick 2.15
Item {
signal mySignal(string message) // 定义信号
// ...
}
- Where the signal needs to be triggered, call
signal
the function marked with the keyword and pass the corresponding parameters.
// MyItem.qml
Button {
text: "Send Signal"
onClicked: {
mySignal("Hello from QML") // 点击按钮出触发信号
}
}
- 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;
}
- 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();
}
- In QML,
Connections
elements 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 MyItem
define a mySignal
signal named in QML. When the button is clicked, we call mySignal
the function and pass it a parameter. In C++, we create an MyObject
object named and main.qml
register it in myObject
. Then, in Connections
the element, we bind myItem
the mySignal
signal to myObject
the handleSignal
slot 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 myObject
and handleSignal
the 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:
- Define the signal in a custom object in C++ and
Q_SIGNAL
mark it with a macro. - Where a signal needs to be triggered, call
emit
the function marked with the keyword to send the signal. - In QML,
Connections
elements 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 MyObject
object's function . In QML, elements are used to bind signals to corresponding handlers.handleButtonClicked
buttonClicked
Connections
buttonClicked
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:
- Declare the functions that need to be accessed in QML in the C++ custom object, and use
Q_INVOKABLE
macros to mark them. - 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 MyObject
declared a cppFunction
function 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:
- In QML, use
QtObject
the element to create an object for the function in the QML file, and set a to this objectid
. - In C++, use
QVariant
andQMetaObject
to 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 QtObject
to define a qmlFunction
function called. In C++, we use QMetaObject
and QMetaMethod
to 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!