Qt中自定义数据类型的创建及使用
Date | Author | Version | Note |
---|---|---|---|
2022.12.17 | Dog Tao | V1.0 | 整理后发表。 |
前言
在Qt的项目开发过程中,特别是在制作一些特殊界面时,通常框架中自带的数据类型难已满足具体的要求,这时就需要开发者自己创建新的数据类型来扩展或替换原有的数据类型。本文将详细介绍自定义数据类型的方法以及如何将其集成到Qt对象模型中,为大家提供参考。
特别说明:本文档参考了此篇博文。
创建一个自定义类型
Qt框架下开发时,创建一个自定义类型,需要确保创建的这个自定义类型符合QMetaType
规定的所有要求,即它必须满足以下几个条件:
- 有一个默认的公有构造函数
- 有一个公有的拷贝构造函数
- 有一个公有的析构函数
下面的Message
类的定义满足这些条件,可以定义成一个新的数据类型:
class Message
{
public:
Message();
Message(const Message &other);
~Message();
Message(const QString &body, const QStringList &headers);
QString body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};
这个类还提供了一个带参数的构造函数和用于访问两个私有成员的公有函数。
自定义类型的声明
对于Message
类,仅需要一个简单的实现,即可以使用,但是在Qt框架下,若没有其它的辅助信息,系统将无法理解这个类的存储方式、检索方式以及序列化方式。比如,我们无法将该类的值保存到QVariant
中。因此,我们需要对该类进行声明。
Qt中,负责自定义类型的类是QMetaType
,为了让这个类识别自定义的数据类型,需要在定义Message
类的头文件中使用Q_DECLARE_METATYPE()
宏声明。注意是在”global scope”中调用完成Qt元类型的声明。
class Message
{
/*省略无关内容*/
};
Q_DECLARE_METATYPE(Message);
经过声明后,便可以将Message
类的值保存到QVariant
对象中,以便在项目的其它地方读取。QVariant
对象与自定类型的互相转化可以参考笔者的《使用QSettings保存和读取自定义数据类型》一文中的“QVariant与自定义结构体转化章节”。以下简要说明:
- 自定类型转
QVariant
对象
QVariant Variant_Message = QVariant::fromValue<Message>(Message());
QVariant
对象转自定类型
Message message = Variant_Message.value<Message>();
用Q_DECLARE_METATYPE()
声明的自定义类型, 其对应的值可用作信号SIGNAL()
的参数,但是仅限于DirectConnection
信号槽连接方式。为了能满足全部的信号槽连接方式,我们还需要做一些其它的处理。
自定义对象的创建与销毁
虽然上面声明的自定义类型,可以在DirectConnection
信号槽连接中使用,但是无法用于QueuedConnection
信号连接中,比如,在不同线程间建立的连接。这是因为元对象系统不知道如何在运行时处理自定义类型对象的创建和销毁操作。
为了可以在运行时创建对象,需要调用qRegisterMetaType()
模板函数在元对象系统中注册此类型。只要在使用此类型第一次建立连接前调用注册函数,该类型即可被用于QueuedConnection
信号槽连接。
下面的示例中,在main.cpp
中注册了一个Message
类,而后在Information
类中绑定信号。
//main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc,argv);
//其它项目的代码
qRegisterMetaType<Message>();
//其它项目代码
return a.exec();
}
//下面是Information类的相关调用
Information::Information()
{
informatin_thread = new QThread();
connect(information_thread, SIGNAL(sendMessage(Message)), this, SLOT(receiveMessage(Message)));
//项目的其它代码
}
若类型未经注册而直接绑定在QueuedConnection
信号槽中,则会报如下错误:
QObject::connect: Cannot queue arguments of type ‘Block’ (Make sure ‘Block’ is registered using qRegisterMetaType().)