起因是之前用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需要匹配源码的签名(即 参数列表+返回类型 )
*ctemplate <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时折磨了很久。 等有时间可能回去把它再统一改一次了。
在后面的项目中,得好好规划一下了。