概述
如果想要我们自己自定义的类型也可以有 Qt 自己类型的功能的话,就必须注册我们的类型到 Qt 中,这样才可以在信号和槽的通讯机制中使用我们的自定义的类型。
Q_DECLARE_METATYPE
被 Q_DECLARE_METATYPEQ 标记的类型可以让Q MetaType 查询到类型,也可以让QVariant识别到。
struct MyStruct {
QString name;
};
Q_DECLARE_METATYPE(MyStruct)
若对象包含在自定义的命名空间中时,注册时要带上完整的命令空间
Q_DECLARE_METATYPE(NSP::MyStruct)
qRegisterMetaType
使用 qRegisterMetaType 注册自定义类型到元对象系统中主要作用为 QObject 的属性系统(信号槽)中使用该自定义类型。
一般在第一次定义信号槽连接 connect 前进行注册,参数建议为同名字符串参数:
qRegisterMetaType<MyStruct>("MyStruct");
若已经使用 Q_DECLARE_METATYPEQ 标记过该类型,可以使用其不带参数的版本:
qRegisterMetaType<MyStruct>();
同样的,若对象包含在自定义的命名空间中时,注册时要带上完整的命令空间,如:
qRegisterMetaType<NSP::MyStruct>("NSP::MyStruct");
若要用信号槽传递其引用值,也需要注册:
qRegisterMetaType<MyStruct>("MyStruct&");
若要用信号槽传递其智能指针,也需要注册:
qRegisterMetaType<QSharedPointer<MyStruct>>("QSharedPointer<MyStruct>");
总结
在Qt中,想要使用signal/slot来传递自定义的类型时,需要使用qRegisterMetaType来注册。其原因是:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象。用qRegisterMetaType对自定义的类型进行注册,就是为了告诉Qt如何去做这些事情。
步骤:(以自定义MyDataType类型为例)
1、自定MyDataType 类型,在这个类型的顶部包含:#include <QMetaType>
2、在类型定义完成后,加入声明:Q_DECLARE_METATYPE(MyDataType);
3、在main()函数中注册这种类型:qRegisterMetaType<MyDataType>("MyDataType");
4、如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType<MyDataType>("MyDataType&");
例:
#include <QMetaType>
class MyDataType
{
public:
MyDataType();
MyDataType(int, double);
private:
};
Q_DECLARE_METATYPE(MyDataType);
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<MyDataType>("MyDataType");
qRegisterMetaType<MyDataType>("MyDataType&");
}
不跨线程的话,使用自定义的类型使用signal/slot来传递,没有什么问题。
但如果是跨线程的使用,则没有这么简单。
直接使用的话,会产生下面这种错误:(假定自定义类为MyClass)
QObject::connect: Cannot queue arguments of type 'MyDataType' (Make sure 'MyDataType' is registed using qRegisterMetaType().)
实际运行中也会发现,该信号槽没有起作用。
其实解决方法在错误提示中已经给出了:Make sure 'MyDataType' is registed using qRegisterMetaType().
即使用qRegisterMetaType()将自定义类型进行注册
这里总结使用方法如下:
1、注册位置:在第一次使用此类链接跨线程的signal/slot之前,一般在当前类的构造函数中进行注册;
2、注册方法:在当前类的顶部包含:#include <QMetaType>,构造函数中加入代码:qRegisterMetaType<MyDataType>("MyDataType");
3、Myclass的引用类型需单独注册:qRegisterMetaType<MyDataType>("MyDataType&");
如果不实用这种方法,还有一种办法来使跨线程的signal/slot起作用,即使用connect函数的Qt::DirectConnection参数
connect(A,SIGNAL(sendA(MyDataType)),B,SLOT(getA(MyDataType)),Qt::DirectConnection);
但此方法官方不推荐使用,认为其不安全。不过在笔者实际使用过程中,未发现有不妥之处。
最后
以上就是疯狂樱桃最近收集整理的关于Qt中注册定义类型qRegisterMetaType和Q_DECLARE_METATYPE的总结的全部内容,更多相关Qt中注册定义类型qRegisterMetaType和Q_DECLARE_METATYPE内容请搜索靠谱客的其他文章。
发表评论 取消回复