C++ 单例类注册 QML 调用
·
【Qt 小白必看】C++ 单例类注册 QML 调用(逐行超详细注释+CSDN精品笔记)
这篇笔记是纯小白向,把你写的全部代码逐行、逐字符拆解,讲清单例模式原理 + C++ 与 QML 交互,直接复制就能发布 CSDN!
一、项目整体介绍
这是一个 Qt Quick 项目,实现两个核心功能:
- C++ 单例类:全局唯一实例,QML 可直接调用
- C++ 与 QML 交互:QML 调用 C++ 函数、显示数据、打印日志
- 同时包含单例注册 + 上下文对象注册两种 Qt 交互方式
二、backendclass.h 头文件 逐行解析
作用:声明类、函数、宏,不写具体逻辑
// 头文件保护宏
// 防止同一个头文件被多次包含,导致编译报错(必须写)
#ifndef BACKENDCLASS_H
#define BACKENDCLASS_H
// 包含 Qt 所有对象的基类
// 必须继承 QObject,才能使用信号槽、QML 交互
#include <QObject>
// 包含 QML 引擎头文件
// 用于把 C++ 类注册到 QML 环境
#include <QQmlEngine>
// 自定义类 BackendClass,公开继承 QObject
class BackendClass : public QObject
{
// Qt 核心宏
// 不加这行:无法使用信号槽、Q_INVOKABLE、注册到 QML
Q_OBJECT
public:
// 显式构造函数
// explicit:禁止隐式类型转换,规范写法
// parent = nullptr:父对象为空,Qt 自动管理内存
explicit BackendClass(QObject *parent = nullptr);
// Q_INVOKABLE:Qt 关键宏
// 作用:让这个 C++ 函数可以在 QML 中直接调用
// 函数功能:返回 int 类型数字
Q_INVOKABLE int getnum();
// QML 可调用函数:控制台打印日志
Q_INVOKABLE void printSomething();
// 静态成员函数
// 属于类,不属于对象,用于注册当前类到 QML
static void registerClass();
// 单例提供者函数
// Qt 固定格式:给 QML 返回唯一的单例对象
static QObject* singletonProvider(QQmlEngine *, QJSEngine *);
signals:
// 信号声明区:本案例没有使用信号
};
#endif // BACKENDCLASS_H
三、backendclass.cpp 源文件 逐行解析
作用:实现头文件里声明的所有函数
// 引入自定义头文件,让编译器认识 BackendClass
#include "backendclass.h"
// 引入 Qt 日志打印头文件
#include <QtDebug>
// 静态全局指针:存储单例对象
// static:作用域仅限当前文件
// 初始化为空:表示还没有创建对象
static BackendClass* m_object=nullptr;
// 构造函数实现
// 初始化列表:调用父类 QObject 的构造函数
BackendClass::BackendClass(QObject *parent) : QObject(parent)
{
// 空构造函数
// 单例对象初始化可以写在这里
}
// 实现 getnum 函数
// 功能:返回固定数字 42,给 QML 显示
int BackendClass::getnum()
{
return 42;
}
// 实现 printSomething 函数
// 功能:控制台打印 hello world
void BackendClass::printSomething()
{
qInfo()<<"hello world";
}
// 实现注册函数:将 C++ 类注册为 QML 单例
void BackendClass::registerClass()
{
// Qt 官方函数:注册单例类到 QML
// 参数1:模块名 com.reddit
// 参数2:主版本 1
// 参数3:次版本 0
// 参数4:QML 中使用的对象名 MyBackend
// 参数5:单例提供函数,返回唯一实例
qmlRegisterSingletonType<BackendClass>("com.reddit",1,0,"MyBackend",singletonProvider);
}
// 单例模式核心函数
QObject *BackendClass::singletonProvider(QQmlEngine *, QJSEngine *)
{
// 第一次调用:对象为空 → 创建实例
if(m_object==nullptr)
{
m_object=new BackendClass();
}
// 后续调用:直接返回已创建的对象
// 保证全局只有一个实例 → 单例模式
return m_object;
}
四、main.cpp 程序入口 逐行解析
作用:程序运行的起点,初始化 Qt、注册 C++ 类、加载 QML 界面
// Qt 界面应用基类
#include <QGuiApplication>
// QML 应用引擎
#include <QQmlApplicationEngine>
// QML 上下文:用于注册普通 C++ 对象
#include <QQmlContext>
// 引入辅助类(你项目里的其他类)
#include "backendhelper.h"
// 引入单例类
#include "backendclass.h"
// main 函数:程序唯一入口
int main(int argc, char *argv[])
{
// 设置 Qt 属性:启用高 DPI 缩放
// 适配高分屏,界面不模糊
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
// 创建 Qt 应用程序对象
QGuiApplication app(argc, argv);
// 创建 QML 引擎:管理 QML 界面
QQmlApplicationEngine engine;
// 创建 BackendHelper 类对象(普通对象,非单例)
BackendHelper obj;
// 关键代码!
// 调用单例类的注册函数,把 C++ 单例注册到 QML
BackendClass::registerClass();
// 把普通 C++ 对象注册到 QML 上下文
// cBackendHelper:QML 中使用的对象名
// &obj:C++ 对象地址
engine.rootContext()->setContextProperty("cBackendHelper",&obj);
// 定义 QML 文件路径:从资源文件加载 main.qml
const QUrl url(QStringLiteral("qrc:/main.qml"));
// Qt 连接:监听 QML 对象创建完成
// 如果加载失败,自动退出程序
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
// 加载 QML 界面
engine.load(url);
// 启动 Qt 事件循环,程序保持运行
return app.exec();
}
五、main.qml 界面文件 逐行解析
作用:写 UI 界面,直接调用 C++ 单例函数
// 导入 QtQuick 基础控件模块
import QtQuick 2.12
// 导入按钮、输入框等高级控件
import QtQuick.Controls 2.5
// 导入 C++ 注册的单例模块
// 对应 C++ 中的 com.reddit 1.0
import com.reddit 1.0
// 应用程序主窗口
ApplicationWindow {
id: window // 窗口唯一标识
visible: true // 窗口显示
width: 640 // 宽度
height: 480 // 高度
title: qsTr("Stack") // 窗口标题
// 文本控件:显示 C++ 返回的数字
Text{
id:mytext // 唯一标识
anchors.centerIn: parent // 居中显示
font.pointSize: 15 // 字体大小
// 核心:调用 C++ 单例函数
// MyBackend:注册的单例对象名
// getnum():C++ 函数,返回 42
text: MyBackend.getnum()
}
// 按钮控件
Button{
id:myButton
text: "Click Me" // 按钮文字
anchors.top: mytext.bottom // 位于文本下方
anchors.horizontalCenter:parent.horizontalCenter // 水平居中
anchors.topMargin: 10 // 间距 10px
// 点击事件
onClicked: {
// 调用 C++ 函数:打印日志
MyBackend.printSomething()
}
}
}
六、小白必懂:单例模式到底是什么?
1. 单例模式定义
一个类,全局只能创建唯一一个对象,全程共享这个对象。
2. 本项目单例实现步骤
- 定义一个静态指针
m_object保存对象 - 第一次调用时
new创建对象 - 之后所有调用直接返回已创建的对象
- QML 无论在哪里使用
MyBackend,都是同一个 C++ 对象
3. 单例优点
- 节约内存
- 全局数据统一
- 避免多次创建对象
七、小白必背核心关键字
Q_OBJECT:启用 Qt 元对象系统Q_INVOKABLE:QML 调用 C++ 函数必备qmlRegisterSingletonType:注册 C++ 单例到 QMLstatic:实现单例的核心关键字singletonProvider:Qt 单例提供函数setContextProperty:注册普通 C++ 对象到 QML
八、项目运行效果
- 界面显示文本:42(来自 C++ 单例函数)
- 界面显示按钮:Click Me
- 点击按钮 → 控制台打印:hello world
- C++ 单例对象全程只创建一次
九、小白常见报错解决
- QML 提示 MyBackend is undefined
→ main.cpp 未调用BackendClass::registerClass() - C++ 函数 QML 调用失败
→ 函数未加Q_INVOKABLE - 编译报错
undefined reference to vtable
→ 类未加Q_OBJECT - 单例失效
→ 静态指针未判断空
十、总结
这是 Qt 入门 C++ 与 QML 交互 + 单例模式 最标准的实战代码:
- C++ 单例类 + 注册到 QML
- QML 直接调用 C++ 函数
- 全局唯一实例,高效安全
- 同时学会单例注册 + 上下文对象注册两种交互方式
逐行吃透这篇笔记,你就掌握了 Qt 开发最核心的基础技能!
更多推荐



所有评论(0)