Qt qml创建c++类的单例对象

起因是之前用setContextProperty注册全局变量使用多了发现麻烦的点很多。

首先就是容易创建多个实例,发现不对后还得一个个打印地址检查,去找自己在哪又去new了这个对象。

只能说有适用的场景,但我之前无脑的用在需要保持单个实例的情景下确实逆天了,接下来记录一下用的新方法:

一、创建c++类的头文件和cpp文件

依旧继承QObject,然后在路径中输入想要创建的文件夹去管理.h和.cpp文件*(这样qt才会帮你去本地创建新文件夹)*

二、 示例代码

在里面写点示例代码,来验证后续是否成功将其注册为单例

c 复制代码
//testsingleton.h

#ifndef TESTSINGLETON_H
#define TESTSINGLETON_H

#include <QObject>

class testSingleton : public QObject
{
    Q_OBJECT
public:
    explicit testSingleton(QObject *parent = nullptr);

    Q_INVOKABLE  int get_Cur();

signals:


private:
    int cur=0;
};

#endif // TESTSINGLETON_H

在cpp中递增一下cur,以供检验数据一致性

c 复制代码
//testsingleton.cpp

#include "testsingleton.h"

testSingleton::testSingleton(QObject *parent)
    : QObject{parent}
{}

int testSingleton::get_Cur()
{
    return cur+=1;
}

三、注册单例

在main.cpp中引入c++类,并将其注册为单例。

  • 引入用的路径可以在CMakeLists中查看,将其复制过来即可
c 复制代码
//CMakeLists

qt_add_qml_module(apptest
    ...
    SOURCES Ctest/testsingleton.h Ctest/testsingleton.cpp
)
  • 理所当然的,要在加载engine前注册单例
c 复制代码
//main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "Ctest/testsingleton.h"

int main(int argc, char *argv[])
{
    ......
    
    qmlRegisterSingletonType<testSingleton>("single",1,0,"Single_example",[](QQmlEngine*,QJSEngine*){		//疑点
    							//依次为:(QML模块名、主版本号、次版本号、QML中的类型名、可调用对象)
        return new testSingleton();					//返回唯一实例
    });

    engine.load(url);

    return app.exec();
}

疑点:为什么参数类型得是(QQmlEngine*,QJSEngine*)呢?

  • 解:这个按住ctrl点一下,看眼源码其实就知道了,写的lambda需要匹配源码的签名(即 参数列表+返回类型
    *

    c 复制代码
    template <typename T>
    int qmlRegisterSingletonType(
    const char *uri, int versionMajor, int versionMinor, const char *typeName,
    std::function<QObject *(QQmlEngine *, QJSEngine *)> callback)

三、qml调用验证

最后在不同qml文件中调用get_Cur方法,查看结果是否会保留另个qml文件中已经递增的数据

  • 先在main.qml中,自动调用一次get_Cur
    *

    c 复制代码
    //main.qml
    
    import test 1.0
    import single 1.0
    
    Window {
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    	
    	TestMd{
        	anchors.centerIn: parent
    	}
    	
    	...
    	
        Component.onCompleted: {
            console.log("first is : ",Single_example.get_Cur())
        }
    }
  • 然后在另一个qml文件中,每次按下按钮调用一次get_Cur
    *

    c 复制代码
    //TestMd.qml
    
    import QtQuick
       import QtQuick.Controls
       import single 1.0
       
       Rectangle {
           width: 200
           height: 100
           color: "blue"
       
           Button {
               anchors.centerIn: parent
               text: "button"
               width: 80
               height: 60
               onClicked: {
                   console.log("clicked is : ",Single_example.get_Cur())
               }
           }
       }

四、输出结果

进行的操作是:程序运行后,点击一次按钮

然后输出是:

过程是:

  • 初始化时cur=0
  • main.qml加载完成后自动调用一次,使得cur=1
  • 按钮的click事件调用一次,使得cur=2

由此我们也能够看出,是成功的创建完成了单例对象的。

五、另一方法(Qt 6.2+)

在询问gpt时,它给出了另一个更简便的api,直接替换qmlRegisterSingletonType,如下所示:

c 复制代码
auto *obj = new testSingleton();
qmlRegisterSingletonInstance("single", 1, 0, "Single_example", obj);
  • 区别:
qmlRegisterSingletonType qmlRegisterSingletonInstance
懒加载,创建时再回调函数 简单快捷,开始就直接创建好

六、总结

全局和单例使用的情景大不相同,之前的错误使用让我排bug时折磨了很久。 等有时间可能回去把它再统一改一次了。

在后面的项目中,得好好规划一下了。

相关推荐
汉克老师27 分钟前
GESP5级C++考试语法知识(六、链表(一)单链表)
c++·链表·单链表·快慢指针·进阶·gesp5级·gesp五级
m0_5180194834 分钟前
C++与机器学习框架
开发语言·c++·算法
ZTLJQ37 分钟前
深入理解逻辑回归:从数学原理到实战应用
开发语言·python·机器学习
qq_4176950541 分钟前
C++中的代理模式高级应用
开发语言·c++·算法
学嵌入式的小杨同学1 小时前
STM32 进阶封神之路(十九):ADC 深度解析 —— 从模拟信号到数字转换(底层原理 + 寄存器配置)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
xiaoye-duck1 小时前
《算法题讲解指南:动态规划算法--路径问题》--5.不同路径,6.不同路径II
c++·算法·动态规划
ambition202421 小时前
最大子数组和算法全解析:从暴力枚举到动态规划优化
数据结构·c++·算法
波波0071 小时前
每日一题:.NET 中的“反射”是什么?
开发语言·.net
qq_461489332 小时前
C++与Qt图形开发
开发语言·c++·算法
Evand J2 小时前
【三维飞行器】RRT路径规划与TOA定位仿真系统,MATLAB例程,路径起终点、障碍物、TOA锚点等均可设置。附下载链接
开发语言·matlab·无人机·定位·rrt·toa·三维航迹规划