【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");
    // 获取自定义类型ID
    int 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 的元类型 ID
    int 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 的各种机制进行集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/123780.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

三菱FX3U系列—原点回归指令

目录 一、简介 二、指令形式 1、原点指令[ZRN/DZRN] 2、带搜索的原点回归指令[DSZR] 三、回归指令运行过程 1、ZRN原点回归运行过程 2、带搜索的原点回归运行过程 四、特殊辅助继电器 五、特殊输出模块 六、总结 一、简介 用于将电机或伺服驱动器控制的轴回到预定的原…

浙江大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;主页 | 教育漏洞报告平台 兑换价格&#xff1a;20金币 获取条件&#xff1a;提交浙江大学任意中危或以上级别漏洞

socks5代理和https代理有什么不同?各自有哪些优点?

socks5代理和https代理是两种不同的代理服务&#xff0c;它们在实现方式、安全性和协议特点等方面存在差异。下面我们来详细了解一下这两种代理的优点。 一、socks5代理的优点 1. 速度快 socks5代理采用了TCP协议&#xff0c;能够有效地减少网络延迟和数据传输速度慢的问题&…

Ubuntu22.04下挂载共享文件夹

1.在自己Windows任意地方建一个文件夹 2.打开虚拟机做如下配置 3.开启虚拟机&#xff0c;打开终端 4.输入&#xff1a;vmware-hgfsclient 看到物理机共享文件夹 5.输入&#xff1a;sudo mkdir /mnt/hgfs 创建虚拟机中的共享文件夹 6.输入&#xff1a;sudo vmhgfs-fuse .h…

离散数学第一章知识点复习

命题&#xff1a;陈述句 真值已经确定 原子命题&#xff08;简单命题&#xff09;&#xff1a;不能被分解为更简单的命题 命题化的时候的解题步骤&#xff1a; 1. 先给出原子命题 2. 符号化 注意蕴含式&#xff1a;记作 p -> q &#xff0c;p是前件&#xff0c;q 是后…

软件版本控制系统VCS工具——cvs vss svn git

版本控制 版本控制系统&#xff08;Version Control System&#xff0c;VCS&#xff09;是用于跟踪和管理源代码和文档的工具。可追踪和管理修改历史&#xff0c;包括修改的内容、时间、作者等信息。有助于团队协作、追踪变更、恢复历史版本等。VCS的主要目的是帮助团队协作开…

如何写一篇吊炸天的竞品分析

这段时间&#xff0c;除了撩妹之外&#xff0c;最多的就是竞品分析了。最近很多临近毕业的同学也在四处应聘产品岗&#xff0c;而一份不错的竞品分析一定能为你的求职加分不少。于是&#xff0c;有着菩萨心肠天使面孔魔鬼身材的我&#xff0c;就来教大家怎么做一份完整的竞品分…

什么是代理IP池?真实测评IP代理商的IP池是否真实?

代理池充当多个代理服务器的存储库&#xff0c;提供在线安全和匿名层。代理池允许用户抓取数据、访问受限制的内容以及执行其他在线任务&#xff0c;而无需担心被检测或阻止的风险。代理池为各种在线活动&#xff08;例如网页抓取、安全浏览等&#xff09;提高后勤保障。 读完…

【Bug】Python利用matplotlib绘图无法显示中文解决办法

一&#xff0c;问题描述 当利用matplotlib进行图形绘制时&#xff0c;图表标题&#xff0c;坐标轴&#xff0c;标签中文无法显示&#xff0c;显示为方框&#xff0c;并报错 运行窗口报错&#xff1a; 这是中文字体格式未导入的缘故。 二&#xff0c;解决方案 在代码import部…

将 Figma 轻松转换为 Sketch 的免费方法

最近浏览网站的时候&#xff0c;发现很多人不知道Figma是怎么转Sketch的。众所周知&#xff0c;Figma支持Sketch文件的导入&#xff0c;但不支持Sketch的导出&#xff0c;那么Figma是如何转Sketch的呢&#xff1f;不用担心&#xff0c;建议使用神器即时设计。它是一个可以实现在…

systemctl enable docker.service报错“Failed to execute operation: Bad message“

将docker加入到开机自启&#xff0c;报错&#xff1a; 解决&#xff1a; 重新粘贴复制&#xff1a; [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target…

在现实生活中传感器GV-H130/GV-21的使用

今天&#xff0c;收获了传感器GV-H130/GV-21&#xff0c;调试探头的用法&#xff0c;下面就来看看吧&#xff01;如有不妥欢迎指正&#xff01;&#xff01;&#xff01;&#xff01; 目录 传感器GV-H130/GV-21外观 传感器调试探头 探头与必要准备工作 传感器数值更改调试 …

Fabric: 使用InvokeChaincode实现跨通道数据访问

因为工作中遇到一些问题考虑使用Fabric的跨通道链码调用方法InvokeChaincode()来解决&#xff0c;这篇文章主要是记录以下在Fabric测试网络中InvokeChaincode()的使用过程及遇到的问题。 1 前期准备 1.1 认识InvokeChaincode InvokeChaincode的作用是调用指定的链码。而被调用…

pytoch安装指定版本教程pytorch1.3安装笔记

一、先生成一个环境 如果电脑里安装了其他的torch版本&#xff0c;另外生成一个环境可以防止原先torch版本被替换掉。 打开conda的终端窗口输入以下命令就可以生成一个名为torch_1.3的环境&#xff1a; conda create -n torch_1.3 python3.6 输入以下命令进入到torch_1.3的…

基于springboot实现致远汽车租赁平台管理系统项目【项目源码+论文说明】

基于springboot实现致远汽车租赁平台系统演示 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要…

linux下实现电脑开机后软件自启动

实现linux的软件自启动&#xff0c;需要四个文件 第一个【displayScreen.desktop】文件&#xff0c;.desktop文件就是一个用来运行程序的快捷方式,也叫启动器&#xff0c;常用来自启动用的文件&#xff0c;内容如下 [Desktop Entry] #要执行的脚本位置 Exec/home/yicaobao/te…

后入能先出,一文搞懂栈

目录 什么是栈数组实现链表实现栈能这么玩总结 什么是栈 栈在我们日常编码中遇到的非常多&#xff0c;很多人对栈的接触可能仅仅局限在 递归使用的栈 和 StackOverflowException&#xff0c;栈是一种后进先出的数据结构(可以想象生化金字塔的牢房和生化角斗场的狗洞)。 栈&…

欧科云链:成本与规模之辨——合规科技如何赋能香港Web3生态?

作为国际金融中心&#xff0c;香港近两年来在虚拟资产及Web3领域频频发力。秉持着“稳步创新”的基本逻辑&#xff0c;香港在虚拟资产与Web3领域已建立一定优势&#xff0c;但近期各类风险事件的发生则让业界的关注焦点再次转向“安全”与“合规”。 在香港FinTech Week前夕&a…

强力解决使用node版本管理工具 NVM 出现的问题(找不到 node,或者找不到 npm)

强力解决使用node版本管理工具 NVM 出现的问题&#xff08;找不到 node&#xff0c;或者找不到 npm&#xff09; node与npm版本对应关系 nvm是好用的Nodejs版本管理工具&#xff0c; 通过它可以方便地在本地调换Node版本。 2020-05-28 Node当前长期稳定版12.17.0&#xff0c;…

基于SSM+Vue的随心淘网管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…