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

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

相关推荐
June`4 小时前
IO模型全解析:从阻塞到异步(高并发的reactor模型)
linux·服务器·网络·c++
古城小栈4 小时前
Rust 已经自举,却仍需GNU与MSVC工具链的缘由
开发语言·rust
YxVoyager4 小时前
Qt C++ :QRegularExpression 正则表达式使用详解
c++·qt·正则表达式
jarreyer4 小时前
数据项目分析标准化流程
开发语言·python·机器学习
闻缺陷则喜何志丹4 小时前
【回文 字符串】3677 统计二进制回文数字的数目|2223
c++·算法·字符串·力扣·回文
李余博睿(新疆)4 小时前
c++分治算法
c++
你怎么知道我是队长4 小时前
C语言---printf函数使用详细说明
c语言·开发语言
qq_401700414 小时前
QStackedLayout 实现遮罩层
qt
liulilittle4 小时前
俄罗斯访问欧洲国际线路优化
开发语言·网络·信息与通信·ip·通信·俄罗斯·莫斯科