QML与C++交互
QML 与 C++ 的交互是 Qt Quick 开发的核心需求,常用于将界面逻辑与底层业务逻辑解耦。
一、基础交互原理
- 核心机制:通过 Qt 元对象系统(Meta-Object System)实现 QML 与 C++ 的双向通信,依赖信号槽(Signals & Slots)和属性绑定(Property Binding)。
注册方式:qml中setContextProperty、qt c++中qmlRegisterTypeQQmlApplicationEngine engine; MyObject myObject; engine.rootContext()->setContextProperty("myObject", &myObject);
qmlRegisterType<MyObject>("MyObjectLib", 1, 0, "MyObject");
- 数据类型映射:QML 自动转换基础类型(如
int
、QString
),复杂类型需注册为元类型(如QJsonObject
)。
二、常见交互方式
1、暴露 C++ 对象到 QML 上下文。
cpp
// C++ 类
class DataManager : public QObject {
Q_OBJECT
public:
Q_INVOKABLE void saveData(const QString &content);
};
// 主函数中注册
int main() {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
DataManager manager;
engine.rootContext()->setContextProperty("dataManager", &manager); // 关键步骤
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
qml
// QML 调用
Button {
onClicked: dataManager.saveData("Hello QML!")
}
2、注册 C++ 类为 QML 类型。
cpp
// 定义可导出的 C++ 类
class Calculator : public QObject {
Q_OBJECT
Q_PROPERTY(int result READ result NOTIFY resultChanged) // 属性暴露
public:
Q_INVOKABLE int add(int a, int b) { return a + b; }
signals:
void resultChanged();
private:
int result;
};
// 在 main.cpp 注册
qmlRegisterType<Calculator>("MyLib", 1, 0, "Calculator");
qml
// QML 中使用
import MyLib 1.0
Calculator {
id: calc
onResultChanged: console.log("New result:", result)
}
Button {
onClicked: calc.result = calc.add(10, 20)
}
3、使用 QJSValue
传递函数,异步回调。
cpp
class CallbackHandler : public QObject {
Q_OBJECT
public:
Q_INVOKABLE void registerCallback(QJSValue func) {
m_callback = func;
}
void trigger() {
if (m_callback.isCallable())
m_callback.call();
}
private:
QJSValue m_callback;
};
qml
// QML 传递回调函数
CallbackHandler {
id: handler
Component.onCompleted: handler.registerCallback(() => console.log("Called!"))
}
4、通过 Q_PROPERTY
实现属性绑定,自动同步 C++ 与 QML 的数值变化。
cpp
class Settings : public QObject {
Q_OBJECT
Q_PROPERTY(bool darkMode READ darkMode WRITE setDarkMode NOTIFY darkModeChanged)
public:
bool darkMode() const { return m_darkMode; }
void setDarkMode(bool enabled) {
if (m_darkMode != enabled) {
m_darkMode = enabled;
emit darkModeChanged();
}
}
signals:
void darkModeChanged();
private:
bool m_darkMode = false;
};
qml
// QML 双向绑定
Switch {
checked: settings.darkMode
onCheckedChanged: settings.darkMode = checked
}
三、实例
1、实例(qml中setContextProperty注册方式)
1)、创建一个空的Qt Quick程序。创建后,基本目录结构如下:
2)、打开main.cpp,进行修改。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QObject>
#include <QDebug>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
public:
QString message() const {
return m_message;
}
void setMessage(const QString& qMsg){
m_message = qMsg;
}
public slots:
void sayHello() {
m_message = "Hello from C++!";
qDebug() << m_message; // 终端中打印
emit messageChanged();
}
signals:
void messageChanged();
private:
QString m_message="hello init";
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyObject myObject;
engine.rootContext()->setContextProperty("myObject", &myObject);
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
#include "main.moc"
3)、打开main.qml,进行修改。
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: 400
height: 300
title: "QML and C++ Interaction"
Button {
text: "Click Me"
onClicked: {
myObject.sayHello(); // 调用C++对象的函数
console.log("调用C++对象的函数\n");
}
}
Label {
id: label1
visible: true
text: myObject.message // 显示从C++传递的消息
anchors.centerIn: parent
}
}
4)、生成效果如下:
2、实例(qt c++中qmlRegisterType注册方式)
1)、创建一个空的Qt Quick程序。创建后,基本目录结构如下:
2)、打开main.cpp,进行修改。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QObject>
#include <QDebug>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY messageChanged)
public:
QString message() const {
return m_message;
}
void setMessage(const QString& qMsg){
m_message = qMsg;
}
public slots:
void sayHello() {
m_message = "Hello from C++!";
qDebug() << m_message; // 终端中打印
emit messageChanged();
}
signals:
void messageChanged();
private:
QString m_message="hello init";
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<MyObject>("MyObjectLib", 1, 0, "MyObject");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
#include "main.moc"
3)、打开main.qml,进行修改。
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import MyObjectLib 1.0
ApplicationWindow {
visible: true
width: 400
height: 300
title: "QML and C++"
MyObject{
id: testObj
}
Button {
text: "Click Me"
onClicked: {
testObj.sayHello(); // 调用C++对象的函数
console.log("调用C++对象的函数\n");
}
}
Label {
id: label1
visible: true
text: testObj.message // 显示从C++传递的消息
anchors.centerIn: parent
}
}
4)、生成效果如下: