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时折磨了很久。 等有时间可能回去把它再统一改一次了。

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

相关推荐
Hhy_110739 分钟前
《C++深度解构06》手撕 string —— 从底层内存管理到深浅拷贝彻底吃透
c语言·开发语言·c++·学习·visual studio
starzy199044 分钟前
深入理解Scala函数定义:从方法到函数的类型跨越
开发语言·scala
starzy19901 小时前
深入理解Scala递归函数:从栈溢出到尾调用优化
开发语言·scala
三*一1 小时前
Mapbox‑GL JS 多边形折点编辑工具:实现原理、功能拆解与踩坑总结
开发语言·javascript·ecmascript
青少儿编程课堂1 小时前
蓝桥杯青少组图形化省考报名倒计时·全国青少年信息素养大赛·电子学会图形化考级:校园黑白棋人机对战解析
c++·python·算法·bfs·信息学竞赛
YSL0701241 小时前
C++基础
开发语言·c++
若亦_1 小时前
Java中关于this的三种用法
java·开发语言·intellij-idea
2601_968793142 小时前
Python Requests 轻量自动化:无需浏览器,实现真人级账号浏览模拟
开发语言·python·自动化
eggwyw2 小时前
关于C++为什么不加入垃圾回收机制解析
开发语言·c++
曦樂~12 小时前
Cpp面筋
c语言·c++