当前位置: 首页 > news >正文

【Qt之QMetaType】使用

介绍

QMetaType类管理元对象系统中的命名类型。
该类用作QVariant和排队的信号与槽连接中类型的编组辅助器。它将类型名称与类型关联起来,以便可以在运行时动态创建和销毁它。使用Q_DECLARE_METATYPE()声明新类型,以使它们可供QVariant和其他基于模板的函数使用。调用qRegisterMetaType()使类型可供非基于模板的函数使用,例如排队的信号和槽连接。
可以注册具有公共默认构造函数、公共复制构造函数和公共析构函数的任何类或结构。
以下代码分配并销毁MyClass的实例:

  int id = QMetaType::type("MyClass");if (id != QMetaType::UnknownType) {void *myClassPtr = QMetaType::create(id);...QMetaType::destroy(id, myClassPtr);myClassPtr = 0;}else{}

以上代码输出是:
MyClass类型未注册,则输出else语句里的内容,如果注册此类型,则输出if语句里的内容。

如果我们希望流运算符operator<<()operator>>()可以在存储自定义类型的QVariant对象上工作,则自定义类型必须提供operator<<()operator>>()运算符。

type()方法

该函数的功能是返回一个句柄(handle),该句柄指向名为 typeName 的类型(type),如果没有这样的类型,则返回 QMetaType::UnknownType

该函数可以用于在运行时(runtime)根据类型名称查找类型的元信息(meta information),并返回一个句柄以便在程序中使用该类型。如果找不到该类型,则返回一个无效句柄。

该函数属于 Qt 框架中的 QMetaType 类,用于支持动态类型(dynamic typing)。
该代码定义了 Qt 框架中的 QMetaType 类,其包含了许多用于类型信息的获取、操作和转换的成员和静态函数。

常用方法

枚举类型
类型枚举解释
TypeVoid、Bool、Int、UInt 和 UnknownType 等表示空类型、布尔类型、整型、无符号整型和未知类型。
TypeFlagNeedsConstruction、NeedsDestruction、MovableType、IsEnumeration 和 PointerToQObject 等用于表示类型的构造、析构方法需要的标识、可移动性、枚举和 QObject 指针等特征。

flags 类型 TypeFlags 是 TypeFlag 的位域版本,用于标识多个特性。

公共函数
  1. QMetaType(int typeId) 构造函数。

  2. ~QMetaType() 析构函数。

  3. void* construct(void* where, const void* copy = Q_NULLPTR) const 在给定的内存位置 where 建立一个新对象,可选择提供已有对象作为参数 copy。返回指向新对象的指针。

  4. void* create(const void* copy = Q_NULLPTR) const 创建一个新对象,可选择提供已有对象作为参数 copy。返回指向新对象的指针。

  5. void destroy(void* data) const 销毁给定对象指针 data 指向的对象。

  6. void destruct(void* data) const 对给定内存位置的对象进行析构。

  7. TypeFlags flags() const 返回类型的特性标识。

  8. bool isRegistered() const 检查该类型是否已注册。

  9. bool isValid() const 检查该类型是否有效。

  10. const QMetaObject* metaObject() const 返回类型的元对象。

  11. int sizeOf() const 返回该类型所需的内存大小。

静态公共成员
  1. bool compare(const void* lhs, const void* rhs, int typeId, int* result) 比较给定的两个对象 lhs 和 rhs 是否相等,并将结果存储在 result 中。

  2. void* construct(int type, void* where, const void* copy) 构造给定类型的对象,并将结果存储在 where 中。

  3. bool convert(const void* from, int fromTypeId, void* to, int toTypeId) 将 from 类型的对象转换成 toTypeId 类型的对象,并将结果存储在 to 中。

  4. void* create(int type, const void* copy = Q_NULLPTR) 创建指定类型的新对象,并可使用给定的 copy 作为初始化值。

  5. bool debugStream(QDebug& dbg, const void* rhs, int typeId) 输出给定类型对象 rhs 的调试信息。

  6. void destroy(int type, void* data) 销毁指定类型的给定对象 data。

  7. void destruct(int type, void* where) 析构指定类型的对象。

  8. bool equals(const void* lhs, const void* rhs, int typeId, int* result) 比较给定类型的两个对象 lhs 和 rhs 是否相等,并将结果存储在 result 中。

  9. bool hasRegisteredComparators() 检查是否已注册比较器。

  10. bool hasRegisteredComparators(int typeId) 检查是否为给定类型已注册比较器。

  11. bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId) 检查是否已注册转换函数。

  12. bool hasRegisteredConverterFunction() 检查是否已注册任何转换函数。

  13. bool hasRegisteredDebugStreamOperator() 检查是否已注册调试输出函数。

  14. bool hasRegisteredDebugStreamOperator(int typeId) 检查是否为给定类型已注册调试输出函数。

  15. bool isRegistered(int type) 检查是否已注册给定类型。

  16. bool load(QDataStream& stream, int type, void* data) 从数据流 stream 中加载给定类型的对象 data。

  17. const QMetaObject* metaObjectForType(int type) 返回与给定类型关联的元对象。

  18. bool registerComparators() 注册比较器。

  19. bool registerConverter() 注册转换函数。

  20. bool registerConverter(MemberFunction function) 注册成员函数类型的转换函数。

  21. bool registerConverter(MemberFunctionOk function) 注册成员函数类型的转换函数,但不进行类型检查。

  22. bool registerConverter(UnaryFunction function) 注册一元函数类型的转换函数。

  23. bool registerDebugStreamOperator() 注册调试输出函数。

  24. bool registerEqualsComparator() 注册比较器。

  25. bool save(QDataStream& stream, int type, const void* data) 将给定类型的对象 data 写入到数据流 stream 中。

  26. int sizeOf(int type) 返回给定类型所需的内存大小。

  27. int type(const char* typeName) 返回给定类型名称的类型 ID。

  28. int type(const QByteArray& typeName) 返回给定类型名称的类型 ID。

  29. TypeFlags typeFlags(int type) 返回给定类型的特性标识。

  30. const char* typeName(int typeId) 返回给定类型 ID 的类型名称。

非成员函数
  1. int qMetaTypeId() 返回 QObject 类型的类型 ID。

  2. int qRegisterMetaType(const char* typeName) 注册给定类型名称的元类型,并返回其类型 ID。

  3. int qRegisterMetaType() 注册调用者的类型为元类型,并返回其类型 ID。

  4. void qRegisterMetaTypeStreamOperators(const char* typeName) 为给定类型名称注册流处理函数。

宏定义
  1. Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(Container) 声明关联式容器的元类型。

  2. Q_DECLARE_METATYPE(Type) 声明元类型。

  3. Q_DECLARE_OPAQUE_POINTER(PointerType) 声明不透明指针的元类型。

  4. Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(Container) 声明顺序容器的元类型。

  5. Q_DECLARE_SMART_POINTER_METATYPE(SmartPointer) 声明智能指针的元类型。

示例

#include <QMetaType>
#include <QDebug>// 自定义类型
class MyType {
public:MyType(){}MyType(int value) : m_value(value) {}int value() const { return m_value; }
private:int m_value;
};// 注册自定义类型
Q_DECLARE_METATYPE(MyType)int main()
{qRegisterMetaType<MyType>("MyType");// 获取自定义类型IDint typeID = QMetaType::type("MyType");if (typeID == QMetaType::UnknownType) {qDebug() << "MyType is not a registered type";return -1;}// 创建自定义类型对象void* obj = QMetaType::create(typeID, new MyType(42));MyType* myObj = static_cast<MyType*>(obj);qDebug() << "Value of myObj: " << myObj->value();// 析构自定义类型对象QMetaType::destroy(typeID, obj);delete myObj;return 0;
}

结果:
在这里插入图片描述
该示例中,

  • 使用 Q_DECLARE_METATYPE 宏在全局命名空间中声明了 MyType 类型是元类型。
  • 通过 QMetaType::type 函数获取 MyType 的类型 ID,如果返回值为 QMetaType::UnknownType,则说明该类型没有被注册过。

在 main 函数中,

  • 使用 QMetaType::create 函数创建一个 MyType 对象,并使用static_cast转换为 MyType 指针。
  • 输出该对象的值
  • 再使用 QMetaType::destroy 函数析构对象。

Q_DECLARE_METATYPEqRegisterMetaType用法

Q_DECLARE_METATYPEqRegisterMetaType 都是用来注册自定义类型的函数,但用途略有不同。

Q_DECLARE_METATYPE 宏用于在程序中声明自定义类型是一个元类型。这个宏只是为了告诉 Qt 该类型是元类型,并不会实际注册该类型。当使用该类型时,必须保证已经调用了 qRegisterMetaType 函数将该类型注册为元类型。例如:

// 声明自定义类型是元类型
class MyType {};
Q_DECLARE_METATYPE(MyType);int main() {// 注册自定义类型为元类型qRegisterMetaType<MyType>("MyType");// ...
}

qRegisterMetaType 函数用于将自定义类型注册为元类型。它必须在程序中的一个全局作用域中调用。例如,通常将它放在 main 函数中。该函数返回已注册类型的元类型 ID,并且该 ID 可以用于在运行时创建该类型的对象。例如:

class MyType {};
Q_DECLARE_METATYPE(MyType);int main() {// 注册自定义类型为元类型qRegisterMetaType<MyType>("MyType");// 获取 MyType 的元类型 IDint typeID = QMetaType::type("MyType");// 创建 MyType 对象MyType* obj = static_cast<MyType*>(QMetaType::create(typeID));// ...
}

总的来说,当你需要在运行时创建某一类型的对象,或者将某一类型用作 Qt 信号/槽中的参数或返回值时,就需要使用 qRegisterMetaType 函数来将该类型注册为元类型。而在该类型的定义头文件中,使用 Q_DECLARE_METATYPE 宏只是为了在程序中声明该类型是元类型。

使用场景

QMetaType 主要用于将 Qt 的信号与槽机制与自定义类型集成。在 Qt 中,信号与槽可以连接任何可转换为 QObject 指针的对象,但是对于信号与槽之间传输自定义类型的数据,则需要将其注册为元类型。

具体来说,当程序使用自定义类型作为信号与槽的参数或返回值时,需要使用 qRegisterMetaType 函数将该类型注册为元类型,否则程序将无法正常编译与运行。例如:

// 自定义类型
struct MyStruct {int value;
};// 注册自定义类型为元类型
Q_DECLARE_METATYPE(MyStruct);
qRegisterMetaType<MyStruct>("MyStruct");class MyObject : public QObject
{Q_OBJECT
public slots:// 槽函数,参数为 MyStruct 类型的对象void onCustomTypeReceived(MyStruct obj) {qDebug() << obj.value;}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);MyObject obj;// 连接信号与槽,信号参数为 MyStruct 类型的对象QObject::connect(&sender, &Sender::customTypeSent, &obj, &MyObject::onCustomTypeReceived);// ...
}

除了信号与槽之外,QMetaType 还可以用于将自定义类型存储到 QVariant 对象中,以及在 QDataStream 中传输自定义类型等场景。总的来说,QMetaType 的主要作用是通过将自定义类型注册为元类型,使其能够与 Qt 的各种机制进行集成。

相关文章:

  • 刷题笔记day16-二叉树的深度
  • 11-08 周三 图解机器学习之实现逻辑异或,理解输出层误差和隐藏层误差项和动量因子
  • 使用LogBack替换Log4j
  • HarmonyOS开发:回调实现网络的拦截
  • Kotlin与Java写法的变更
  • 搭建自己的MQTT服务器,实现设备上云(Ubuntu+EMQX)
  • 合肥工业大学数据库实验报告
  • Ripro-V5 6.4最新版 不限域名无限搭建(授权激活文件)
  • springboot引入外部jar,package打包报错找不到程序包XXX
  • MySQL的表格去重,史上最简便的算法,一看就会
  • 汽车标定技术(六)--基于模型开发如何生成完整的A2L文件(2)
  • 11.8知识总结(web应用程序、手写web框架、Django框架等)
  • 2023.11.09 homework
  • 2. Spark报错,Task is Failed,errorMsg: FileNotFoundException xxxx
  • uniapp刻度尺的实现(swiper)滑动打分器
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 2017 前端面试准备 - 收藏集 - 掘金
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • canvas 五子棋游戏
  • JavaScript对象详解
  • JavaScript类型识别
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • October CMS - 快速入门 9 Images And Galleries
  • Spark RDD学习: aggregate函数
  • SpiderData 2019年2月23日 DApp数据排行榜
  • 翻译--Thinking in React
  • 高度不固定时垂直居中
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 区块链共识机制优缺点对比都是什么
  • 手机端车牌号码键盘的vue组件
  • 学习笔记TF060:图像语音结合,看图说话
  • 字符串匹配基础上
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (附源码)ssm码农论坛 毕业设计 231126
  • (三)模仿学习-Action数据的模仿
  • (四)模仿学习-完成后台管理页面查询
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (一)基于IDEA的JAVA基础10
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)程序员技术练级攻略
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .Net 路由处理厉害了
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net解析传过来的xml_DOM4J解析XML文件
  • .net与java建立WebService再互相调用
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • [ C++ ] STL---stack与queue