在 Qt 应用程序开发中,QML 和 C++ 的结合可以为我们提供强大的数据交互和界面构建能力。QML 主要负责用户界面的展示,而 C++ 则处理业务逻辑和数据。通过 C++ 的信号与槽机制,QML 可以接收来自 C++ 的数据并实时更新界面。
文章源码下载
通过网盘分享的文件:QML实时监控带参信号
链接: https://pan.baidu.com/s/1BdhzcYDltGWw95OJtoTY6g?pwd=jkcf 提取码: jkcf
1. C++ 中的信号和定时器
在 Qt 中,信号与槽机制是 C++ 类与 QML 交互的核心。我们可以在 C++ 类中定义信号,并通过定时器周期性地发送数据。在本例中,我们将创建一个 C++ 类 MyClass
,它包含一个 QTimer
定时器,每秒钟更新一次 JSON 数据,并通过信号将数据发送给 QML。
定义信号与槽
首先,我们在 C++ 类 MyClass
中定义一个信号 messageChanged
,它携带一个 QJsonObject
作为参数。QJsonObject
用来传递每次更新的数据。通过定时器,每秒触发一次 updateMessage
槽函数,生成新的 JSON 数据并发射信号。
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
#include <QDateTime>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = nullptr);
~MyClass();
signals:
// 定义一个带参数的信号,参数为 JSON 对象
void messageChanged(const QJsonObject &message);
public slots:
// 一个槽,用于启动定时器
void startTimer();
private slots:
// 定时器槽,每次触发时更新 JSON 数据并发射信号
void updateMessage();
private:
QTimer *timer; // 定时器
};
#endif // MYCLASS_H
在 MyClass
类中,我们使用 QTimer
来设置一个定时器,每秒更新一次数据,并通过 messageChanged
信号将数据发送给 QML。
定时器触发更新数据
在实现文件 MyClass.cpp
中,我们连接定时器的 timeout
信号到 updateMessage
槽函数。每次触发时,生成一个新的 JSON 对象,包含当前时间和消息内容,并通过信号发射到 QML。
#include "MyClass.h"
#include <QDebug>
MyClass::MyClass(QObject *parent) : QObject(parent), timer(new QTimer(this))
{
// 设置定时器,每隔 1 秒触发一次
connect(timer, &QTimer::timeout, this, &MyClass::updateMessage);
}
MyClass::~MyClass()
{
// 确保定时器被销毁前停止
if (timer->isActive()) {
timer->stop();
}
}
void MyClass::startTimer()
{
// 启动定时器
if (!timer->isActive()) {
timer->start(1000); // 1000 毫秒 = 1 秒
}
}
void MyClass::updateMessage()
{
// 创建一个 JSON 对象,每次更新时设置不同的值
QJsonObject jsonObject;
jsonObject["timestamp"] = QDateTime::currentDateTime().toString();
jsonObject["message"] = QString("Updated at: %1").arg(QDateTime::currentDateTime().toString());
// 发射带有 JSON 格式的信号
emit messageChanged(jsonObject);
}
在此代码中,定时器每秒触发一次,updateMessage
函数会创建一个新的 QJsonObject
,并将当前的时间戳和消息发送给 QML。通过 emit messageChanged(jsonObject);
,信号携带 JSON 数据发射出去。
2. QML 中的信号监听
在 QML 中,我们可以通过 Component.onCompleted
来确保 QML 加载完成后立即连接到 C++ 类中的信号。通过连接信号,QML 可以实时接收到来自 C++ 的数据,并进行相应的处理和展示。
监听 C++ 信号
在 QML 中,我们通过 myClass.messageChanged.connect(onMessageChanged)
来连接 C++ 类中的信号。一旦 C++ 发射信号,QML 中的 onMessageChanged
函数就会被触发,接受 JSON 数据,并将其展示出来。
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 640
height: 480
// 在 QML 中监听 C++ 类的信号
Component.onCompleted: {
myClass.messageChanged.connect(onMessageChanged);
}
// 处理信号的槽
function onMessageChanged(message) {
// 输出 JSON 格式的消息
console.log("Received JSON message:", message);
console.log("Timestamp:", message.timestamp);
console.log("Message:", message.message);
}
// 按钮用于触发 C++ 类中的方法
Button {
text: "Start Timer"
anchors.centerIn: parent
onClicked: {
// 启动定时器
myClass.startTimer();
}
}
}
在 QML 代码中,我们使用 messageChanged.connect(onMessageChanged)
来连接信号。当信号触发时,onMessageChanged
函数会接收到 JSON 数据,并通过 console.log
打印出来。我们还为界面添加了一个按钮,点击按钮后将启动 C++ 类中的定时器。
3. 将 C++ 与 QML 结合
为了将 C++ 类与 QML 结合,我们需要在 main.cpp
中进行设置。通过 QQmlApplicationEngine
加载 QML 文件,并将 C++ 对象暴露给 QML。通过 setContextProperty
方法,将 C++ 类中的对象传递给 QML,确保 QML 能够访问这些对象的信号和槽。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "MyClass.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
// 创建 C++ 对象
MyClass myClass;
// 将 C++ 对象暴露到 QML
engine.rootContext()->setContextProperty("myClass", &myClass);
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();
}
在 main.cpp
中,我们创建了 MyClass
对象,并通过 rootContext()->setContextProperty("myClass", &myClass)
将其暴露给 QML。这样,QML 中就可以通过 myClass
访问 C++ 类中的信号和方法。
4. 总结
通过 C++ 和 QML 之间的信号与槽机制,我们能够实现实时的数据反馈。在本例中,我们使用 C++ 中的定时器定期生成 JSON 数据,并通过信号传递给 QML。QML 中通过连接信号,接收数据并更新界面。利用这种方法,我们可以在应用程序中实现动态更新和实时数据处理,增强用户体验。
通过这种方式,C++ 负责复杂的逻辑和数据处理,而 QML 则专注于界面的呈现和用户交互。这种设计模式使得应用程序的开发更加灵活和高效。