一、使用QVariant转换SaveDBDataType saveDBDataType;QVariant data;data.setValue(saveDBDataType);设置数据SaveDBDataType q1 = data.value< SaveDBDataType >();读取数据二、注册数据类型qRegisterMetaType主要是在定义信号槽的时候,传递的参数类型不一定是QT所识别的,QT不识别的就要先注册以下,让QT能够认识,就是用qRegisterMetaType注册qRegisterMetaType< enum dataType>( "enum dataType");qRegisterMetaType< deviceIdType>( "deviceIdType");qRegisterMetaType< electricCableMetaData>( "electricCableMetaData");qRegisterMetaType< uint8_t>( "uint8_t");
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qRegisterMetaType<device_info>("device_info&");
qRegisterMetaType<QList<device_info>>("QList<device_info>&");
MainWindoww;
………………………………
基本理解
- Q_DECLARE_METATYPE
- 如果要使自定义类型或其他非QMetaType内置类型在QVaiant中使用,必须使用该宏。
- 该类型必须有公有的 构造、析构、复制构造 函数
- qRegisterMetaType 必须使用该函数的两种情况
- 如果非QMetaType内置类型要在 Qt 的属性系统中使用
- 如果非QMetaType内置类型要在 queued 信号与槽 中使用
二者关系
二者的代码:
- Q_DECLARE_METATYPE 展开后是一个特化后的类 QMetaTypeId<TYPE>
- qRegisterMetaType 将某类型注册中 MetaType 系统中
二者的联系:
- QMetaTypeId<TYPE>的类中的成员包含对qRegisterMetaType的调用
- 我们知道类中的成员函数并不一定会被调用(即,该宏并不确保类型被注册到MetaType)。
- 通过qRegisterMetaType可以确保类型被注册
两个qRegisterMetaType 的联系
- 无参的qRegisterMetaType函数会通过该成员调用带参数的qRegisterMetaType()
这两个东西真难理清,不妨看看源码吧。
Q_DECLARE_METATYPE
代码来源:src/corelib/kernel/qmetatype.h
#define Q_DECLARE_METATYPE(TYPE) \
QT_BEGIN_NAMESPACE \
template <> \
struct QMetaTypeId< TYPE > \
{ \
enum { Defined = 1 }; \
static int qt_metatype_id() \
{ \
static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \
if (!metatype_id) \
metatype_id = qRegisterMetaType< TYPE >(#TYPE); \
return metatype_id; \
} \
}; \
QT_END_NAMESPACE
- 宏展开是一个在Qt的命名空间中的一个类模板的特化 QMetaTypeId<TYPE>
- 该类含一个enum和一个返回!QMetaType的id的成员函数
qRegisterMetaType(const char *typeName)
代码来源:src/corelib/kernel/qmetatype.h
template
<
typename
T
>
int
qRegisterMetaType
(
const
char
*
typeName
)
{
typedef
void
*(*
ConstructPtr
)(
const
T
*);
ConstructPtr
cptr
=
qMetaTypeConstructHelper
<
T
>;
typedef
void
(*
DeletePtr
)(
T
*);
DeletePtr
dptr
=
qMetaTypeDeleteHelper
<
T
>;
return
QMetaType
::
registerType
(
typeName
,
reinterpret_cast
<
QMetaType
::
Destructor
>(
dptr
),
reinterpret_cast
<
QMetaType
::
Constructor
>(
cptr
));
}
- 该函数的核心就是调用了registerType 函数
- 两个Helper模板函数分别对构造和析构函数进行封装
registerType
代码来源:src/corelib/kernel/qmetatype.cpp
int QMetaType::registerType(const char *typeName, Destructor destructor, Constructor constructor)
函数功能:
- 根据类型名查找其MetaType类型,如果已存在,则直接返回;否则创建后返回。
- 创建一个 !QCustomTypeInfo 对象
- 该对象包含要类型的构造、析构信息,已经规范化后的类型名
- 该对象存入一个全局的!QVector中
qRegisterMetaType()
看manual,可以知道,qRegisterMetaType 还有一个无参的重载函数。
template
<
typename
T
>
inline
int
qRegisterMetaType
()
{
return
qMetaTypeId
(
static_cast
<
T
*>(
0
));
}
- 函数看起来和带参数的那个似乎区别很大(难道不是么?)。
- 手册中告诉我们,执行这个的时候,模板参数T必须用 Q_DECLARE_METATYPE() 声明过
- 能猜到原因吗?注意看前面 Q_DECLARE_METATYPE() 代码,
- 对了。类中的成员函数qt_metatype_id中包含对qRegisterMetaType(typeName)的调用
- 这儿就是辗转调用了这个带参数的qRegisterMetaType函数
unregisterType(const char *typeName)
函数的作用是取消自己先前注册的某个metatype类型。
前面提到注册信息在一个全局的
QVector<QCustomTypeInfo>
中,当取消注册的时候是怎么样的呢?直接删除Vector中相应的项么?源码告诉我们,不是的。
实际是查找到相应的项,清空该项的内容。
for
(
int
v
=
0
;
v
<
ct
->
count
(); ++
v
)
{
if
(
ct
->
at
(
v
).
typeName
==
typeName
)
{
QCustomTypeInfo
&
inf
= (*
ct
)[
v
];
inf
.
typeName
.
clear
();
inf
.
constr
=
0
;
inf
.
destr
=
0
;
inf
.
alias
= -
1
;
}
}
创建一个自定义类型
- 一个公共的默认构造函数
- 一个公共的拷贝构造函数, 和
- 一个公共的析构函数
下列的 "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
;
}
;
这个类同时还提供了一般用途的构造函数和另两个公共用于获取私有数据的成员函数.
将类型声明为QMetaType
"Message" 类仅仅需要一段合适的实现就可以使它成为可用的类. 尽管如此, 如果没有其他辅助信息, Qt类型系统还是无法知道如何保持,读取和序列化此类的实例. 比如, 我们无法将 "Message" 的值保存到
QVariant
中.
Q_DECLARE_METATYPE
(
Message
)
; //如果不成功则在定义全局变量的地方声明,声明的是类也同样可以在代码中使用其指针
创建和销毁自定义对象
尽管上一节中的声明使类型可以在直接信号-槽连接中使用, 但是无法用于队列的信号-槽连接中, 比如在不同线程中的对象之间所建立的连接. 这是因为元对象系统在运行时不知道如何处理自定义类型对象的创建和销毁操作.
为了可以在运行时创建对象, 需要调用模板函数
qRegisterMetaType
() 在元对象系统中注册此类型. 那么只要你在建立使用此类型的第一次连接前调用注册函数, 该类型可被用于队列的信号槽连接.
队列的自定义类型例子
中声明了一个在 "main.cpp" 文件中注册的 "Block" 类:
int
main
(
int
argc,
char
*
argv
[])
{
QApplication app
(
argc, argv
)
;
...
qRegisterMetaType
<
Block
>
()
;
...
return
app.
exec
()
;
}
在文件 "window.cpp" 中, 这个类型后来被用于信号槽连接:
Window
::
Window
()
{
thread
=
new
RenderThread
()
;
...
connect
(
thread, SIGNAL
(
sendBlock
(
Block
))
,
this
, SLOT
(
addBlock
(
Block
)))
;
...
setWindowTitle
(
tr
(
"Queued Custom Type"
))
;
}
如果一个没有注册的类型被用于队列连接中, 在控制台中会输出一条警告信息; 例如:
QObject
::
connect
:
Cannot queue arguments of type
'Block'
(
Make sure
'Block'
is registered
using
qRegisterMetaType
()
.
)