【QT】枚举常用宏到底有什么作用?(Q_ENUM,Q_FLAG,Q_DECLARE_FLAGS,Q_DECLARE_OPERATORS_FOR_FLAGS)

news2024/11/22 6:53:08

目录

  • 1. Q_ENUM宏 与 QMetaEnum类
    • 1.1 Q_ENUM宏的作用
    • 1.2 使用Q_ENUM注意的问题
    • 1.3 在写有关枚举的代码时,我们可能遇到这种情况:需要用到枚举的字符串,该怎么办?
    • 1.4 下面通过一段简单的代码来说明Q_ENUM的作用
  • 2. Q_FLAG宏
    • 2.1 Q_FLAG宏的作用
    • 2.2 Q_DECLARE_FLAGS()宏的作用
    • 2.3 Q_DECLARE_OPERATORS_FOR_FLAGS()宏的作用
    • 2.4 演示代码

1. Q_ENUM宏 与 QMetaEnum类

1.1 Q_ENUM宏的作用

  1. 宏Q_ENUM会向元对象系统注册一个枚举类型

1.2 使用Q_ENUM注意的问题

  1. 使用Q_ENUM之前,必须在类中先声明Q_OBJECT或Q_GADGET宏。
  2. Q_ENUM(枚举类型)必须放在枚举声明之后,放在前面编译器会报错。
  3. Q_ENUM宏引入自Qt5.5版本,之前版本的Qt请使用Q_ENUMS宏,但Q_ENUMS宏不支持QMetaEnum::fromType()函数(这也是Q_ENUMS被弃用的原因)

1.3 在写有关枚举的代码时,我们可能遇到这种情况:需要用到枚举的字符串,该怎么办?

这时就需要用到 Q_ENUM宏 和 QMetaEnum类。
用Q_ENUM声明的枚举,其QMetaEnum注册在外部的QMetaObject中。在5.5版本之前可以使用QMetaObject获取QMetaEnum。

//before Qt5.5
QMetaObject object = MyEnum::staticMetaObject;  //MyEnum是当前类,staticMetaObject返回类的元对象
int index = object.indexOfEnumerator("Orientation");  //Orientation是枚举的类型
QMetaEnum metaEnum = object.enumerator(index);

也可以使用静态函数QMetaEnum::fromType()来获取QMetaEnum。

QMetaEnum metaEnum = QMetaEnum::fromType<MyEnum::Orientation>();  //MyEnum是当前类,Orientation是枚举的类型

通过QMetaEnum对象就可以获得枚举的一些信息以及枚举类型与字符串类型的转换。

1.4 下面通过一段简单的代码来说明Q_ENUM的作用

#include <QDebug>
#include <QDialog>
#include <QMetaEnum>

class MyEnum : public QDialog {
    Q_OBJECT

public:
    enum Orientation {
        Up = 1,
        Down = 2,
        Left = 3,
        Right = 4
    };
    Q_ENUM(Orientation)  //向元对象系统注册枚举类型

    MyEnum(QWidget* parent = 0);
    ~MyEnum();
};
#include "myenum.h"

MyEnum::MyEnum(QWidget* parent) :
    QDialog(parent) {
    //获取QMetaEnum对象的方法1:
    //QMetaObject object = MyEnum::staticMetaObject;  //before Qt5.5
	//int index = object.indexOfEnumerator("Orientation");  //Orientation是枚举的类型
	//QMetaEnum metaEnum = object.enumerator(index);
	
	//获取QMetaEnum对象的方法2:
    QMetaEnum metaEnum = QMetaEnum::fromType<MyEnum::Orientation>();  //通过静态函数fromType获取QMetaEnum对象

    //QMetaEnum会对所有的枚举进行下标编号,从0开始
    QString name = metaEnum.name();                   //枚举名称
    int count = metaEnum.keyCount();                  //枚举数量
    QString keyIndex = metaEnum.key(0);               //下标为0的key
    int valueIndex = metaEnum.value(0);               //下标为0的value
    QString Key = metaEnum.valueToKey(MyEnum::Left);  //通过value得到key
    int value = metaEnum.keyToValue("Left");          //通过key得到value

    qDebug() << "枚举的名称:" << name;
    qDebug() << "枚举的数量:" << QString::number(count);
    qDebug() << "index下标的key值:" << keyIndex;
    qDebug() << "index下标的Value值:" << QString::number(valueIndex);
    qDebug() << "value对应的key值:" << Key;
    qDebug() << "key值对应的Vaule:" << QString::number(value);
}

MyEnum::~MyEnum() {}

在这里插入图片描述
需要知道的是:QMetaEnum会对所有的枚举进行下标编号,从0开始。
       QMetaEnum对枚举的保存是通过key和value的方式进行保存和获取的。
以上代码可以看出Q_ENUM声明的枚举,通过QMetaEnum对象可以获得枚举的许多信息。例如枚举的名称、枚举的数量、枚举的key和value值等等。

2. Q_FLAG宏

2.1 Q_FLAG宏的作用

宏Q_FLAG会向元对象系统注册一个单一的标志类型。
使用宏Q_FLAG声明的枚举,其枚举值可以作为标志,并使用位或操作符(|)进行组合。

如果进行位或操作,那上面的代码中枚举值就不能那样定义,因为位或操作是按照二进制位进行“或运算”,其枚举值的定义需要按照位来定义(即不同的枚举值其二进制的每一位都不同)。例如:

enum Orientation {
        Up = 0x01,   //即0000...0001
        Down = 0x02, //即0000...0010
        Left = 0x04, //即0000...0100
        Right = 0x08 //即0000...1000
};

2.2 Q_DECLARE_FLAGS()宏的作用

Q_DECLARE_FLAGS(Flags, Enum)宏展开为:

 typedef QFlags<Enum> Flags;

QFlags<Enum>是一个模板类,其中Enum是枚举类型,QFlags用于存储枚举值的组合。

传统的 C++ 编程中,通常使用整数来保存 enum 的逻辑运算结果 (与、或、非、异或等),在进行逻辑运算的时候没有进行类型检查,一个枚举类型可以和其他的枚举类型进行逻辑运算,运算的结果可以直接传递给接收参数为整数的函数。

下面看一个例子:

  enum Orientation
    {
        Up = 1,   //即0000...0001
        Down = 2, //即0000...0010
        Left = 4, //即0000...0100
        Right = 8 //即0000...1000
    };
 
    enum Direction
    {
        horizontal = 1,
        vertical = 2
	};

这种操作编译器不会报错:

  	Orientation::Up | Direction::horizontal;  //两个不相关的枚举值做逻辑运算没有意义

对于上面的问题,应该怎么解决?
Qt 中,模板类 QFlags<Enum> 提供了类型安全的方式保存 enum 的逻辑运算结果,来解决上面的问题。

这种方式在 Qt 里很常见,例如设置 QLabel 对齐方式的函数是 QLabel::setAlignment(Qt::Alignment) (typedef QFlagsQt::AlignmentFlag Qt::Alignment),这就意味着传给 setAlignment 的参数只能是枚举 Qt::AlignmentFlag 的变量、它们的逻辑运算结果或者 0,如果传入其他的枚举类型或者非 0 值,编译时就会报错,例如:

label->setAlignment(0); // OK
label->setAlignment(Qt::AlignLeft | Qt::AlignTop); // OK

label->setAlignment(Qt::WA_Hover); // Error: 编译时报错

总之,Q_DECLARE_FLAGS(Flags, Enum)宏将普通结构体Enum重新定义成了一个可以自由进行位或操作的安全的结构体Flags。

2.3 Q_DECLARE_OPERATORS_FOR_FLAGS()宏的作用

  1. Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)赋予了Flags一个全局操作符“|”,没有这个宏语句,Flags量之间进行与操作后的结果将是一个int值,而不是Flags值。这点特别重要。
  2. Q_DECLARE_OPERATORS_FOR_FLAGS必须定义在类外。
  3. Q_DECLARE_OPERATORS_FOR_FLAGS只提供了“或”操作,没有提供“与”“非”操作。
  4. Q_DECLARE_FLAGS和Q_DECLARE_OPERATORS_FOR_FLAGS都是和元对象系统无关的,可以脱离Q_FLAG单独使用,事实上这两个宏在Qt4就已经存在(不确定更早是否存在),而Q_FLAG是在Qt5.5版本才加入的。

2.4 演示代码

#include <QDebug>
#include <QDialog>
#include <QMetaEnum>
#include <QMetaObject>

class MyEnum : public QDialog {
    Q_OBJECT

public:
    enum Orientation {
        Up = 0x01,    //即0000...0001
        Down = 0x02,  //即0000...0010
        Left = 0x04,  //即0000...0100
        Right = 0x08  //即0000...1000
    };
    Q_ENUM(Orientation)
    Q_DECLARE_FLAGS(Orientations, Orientation)
    Q_FLAG(Orientations)

    MyEnum(QWidget* parent = 0);
    ~MyEnum();
};

Q_DECLARE_OPERATORS_FOR_FLAGS(MyEnum::Orientations)
#include "myenum.h"

MyEnum::MyEnum(QWidget* parent) :
    QDialog(parent) {
    QMetaEnum metaEnum = QMetaEnum::fromType<MyEnum::Orientation>();  //通过静态函数fromType获取QMetaEnum对象

    QString name = metaEnum.name();                                    //枚举名称
    int count = metaEnum.keyCount();                                   //枚举数量
    QString keyIndex = metaEnum.key(0);                                //下标为0的key
    int valueIndex = metaEnum.value(0);                                //下标为0的value
    QString Key = metaEnum.valueToKeys(MyEnum::Left | MyEnum::Right);  //通过value得到key
    int value = metaEnum.keysToValue("Up | Down");                     //通过key得到value

    qDebug() << "枚举的名称:" << name;
    qDebug() << "枚举的数量:" << QString::number(count);
    qDebug() << "index下标的key值:" << keyIndex;
    qDebug() << "index下标的Value值:" << QString::number(valueIndex);
    qDebug() << "value对应的key值:" << Key;
    qDebug() << "key值对应的Vaule:" << QString::number(value);
}

MyEnum::~MyEnum() {}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

satellite: 利用TLE动态计算并实时显示多颗卫星的位置及轨迹

本示例的目的是介绍演示如何在vue+satellite项目中利用两行根数动态地计算,并显示多个卫星的位置及轨迹。每秒钟更新一下卫星的位置和角度,加载当前时间到固定时间(如720分钟后)的一段轨迹。 直接复制下面的 vue+openlayers源示例代码,操作2分钟即可运行实现效果 文章目…

DDD领域驱动设计基本理解

DDD是一种软件设计思想和方法论&#xff0c;以领域为核心构建软件设计体系&#xff0c;将业务模型抽象成领域模型进行拆解和封装。本文简要介绍DDD的基本概念和常用的分层设计架构&#xff0c;并结合业务场景进行领域驱动设计的实战分析&#xff0c;以加深理解。 1、DDD领域驱动…

opencv通过轮廓去除虚线

思路&#xff1a; 将虚线膨胀为实线&#xff0c;通过高度和宽度找到轮廓&#xff0c;再将轮廓内的面积涂白色 img cv2.imread(imagePath) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray_test gray.copy() binary_test cv2.adaptiveThreshold(clean_gray(gray_test),25…

做项目,最难搞定的不是甲方爸爸...

早上好&#xff0c;我是老原。 前几天和一个老朋友吃饭的时候&#xff0c;他和我吐槽他上个月做的一个项目&#xff0c;实在太累了&#xff0c;几乎是没日没夜地赶进度&#xff0c;身体都快垮了。 我问他既然时间来不及&#xff0c;为什么不前期就和客户沟通好。 他说其实客…

uni-app 的使用体验总结

框架简介 uni-app 是一个使用 Vue.js (opens new window)开发所有前端应用的框架&#xff0c;开发者编写一套代码&#xff0c;可发布到iOS、Android、Web&#xff08;响应式&#xff09;、以及各种小程序&#xff08;微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝&#xff09;…

【自然语言处理】COLD:中文攻击性言论检测数据集

COLD&#xff1a;A Benchmark for Chinese Offensive Language Detection 文章目录 COLD&#xff1a;A Benchmark for Chinese Offensive Language Detection1 论文出处2 背景2.1 背景介绍2.2 针对问题2.3 创新点 3 数据集构建3.1 数据源3.2 效率改进3.3 数据集分析 4 实验设计…

驱动开发:内核物理内存寻址读写

在某些时候我们需要读写的进程可能存在虚拟内存保护机制&#xff0c;在该机制下用户的CR3以及MDL读写将直接失效&#xff0c;从而导致无法读取到正确的数据&#xff0c;本章我们将继续研究如何实现物理级别的寻址读写。 首先&#xff0c;驱动中的物理页读写是指在驱动中直接读…

LiveGBS流媒体平台GB/T28181功能-海康大华宇视华为NVR等4G摄像头自带物联网卡注册国标平台后看不到设备的时候如何排查及抓包

LiveGBS流媒体平台GB/T28181功能-海康大华宇视华为NVR等4G摄像头自带物联网卡注册国标平台后看不到设备的时候如何排查及抓包 1、设备注册后查看不到1.1、是否是4G|5G摄像头1.2、关闭萤石云1.3、防火墙排查1.4、端口排查1.5、IP地址排查1.6、设备TCP/IP配置排查1.7、设备多网卡…

【Nexus】Maven从Nexus中下载jar包

目录 一、前言二、配置Apache Maven1、在Maven的settings.xml中添加一个镜像配置&#xff0c;并覆盖中央仓库的默认配置 二、创建Maven项目&#xff0c;配置pom文件拉取Nexus中的jar包1、确定配置的Maven的settings.xml是否是上一步修改的settings.xml文件&#xff0c;以及repo…

规划地类、用途分区、空间管制区代码对应表

规划地类、用途分区、空间管制区代码对应表 —the—end—

UE5 与 C++ 入门教程·第一课:角色与 Enhanced Input

本文主要围绕 UE5 新的输入系统&#xff0c;手把手从 0 搭建 Unreal 项目&#xff0c;实现角色的基础移动。 重要提示&#xff1a;众所周知&#xff0c;C 属于编译型语言&#xff0c;因此动态灵活性不足&#xff0c;不过执行效率高&#xff0c;而蓝图简单灵活&#xff0c;却执行…

探索TCC:释放高可用性和弹性事务的潜力

1、TCC简介 分布式事务是指在分布式系统中&#xff0c;多个服务之间需要保证数据的一致性和完整性的场景。传统的单机事务无法满足分布式系统的需求&#xff0c;因此需要引入一种新的事务模型来解决分布式事务问题。 TCC&#xff08;Try-Confirm-Cancel&#xff09;是一种基于…

MySQL的分库分表

分必要不要分库分表&#xff08;通过优化之后还明显影响业务再分&#xff0c;可以通过监控慢查询确定&#xff09; 分库分表的一般条件:单表数据量超过1000w&#xff08;阿里应该是说5000w&#xff09;或者单表数据文件(.ibd)超过20GB&#xff0c;这个很重要&#xff0c;&…

点云配准综述一篇综述《A comprehensive survey on point cloud registration》(翻译)

参照了 2021最新关于点云配准的全面综述 - 知乎&#xff0c;并且加了些自己翻译&#xff0c;全篇的内容可能稍有删减。主要作为个人笔记&#xff0c;阅读了几篇综述&#xff0c;发现这篇是质量较好的&#xff0c;值得花时间细读。 文章分类 文章将配准方法分为了同源配准和不…

JMeter三大重要组件——线程组、取样器、查看结果数(3)

JMeter三大重要组件 一、JMeter三大重要组件——线程组1、作用&#xff1a;JMeter主要通过线程组来运行用户脚本2、在取样器错误后要执行的动作&#xff1a;3、线程属性3、调度器4、setUp线程组和tearDown线程组 二、JMeter三大重要组件——取样器1、基本a、自动重定向和跟随重…

Obsidian多端同步插件LiveSync

网友 Leo 和 Paco反馈&#xff0c;群晖升级到 DSM7.2 &#xff0c;注册表可以搜索镜像&#xff0c;根据 Leo 贴的 /var/packages/Docker/etc/dockerd.json 的内容&#xff0c;DSM7.2 应该是使用了 https://docker.nju.edu.cn 作为注册表镜像&#xff0c;但老苏测试过下面几种情…

易基因:易基因近期染色质免疫共沉淀测序(ChIP-seq)研究成果|项目集锦

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 在生物学研究中&#xff0c;DNA与蛋白质之间的互作&#xff08;DNA-Protein Interactions&#xff0c;DPIs&#xff09;是至关重要的&#xff0c;参与基因的表达、调控、复制、重组和修复…

m 序列(最长线性反馈移位寄存器序列)详解

本专栏包含信息论与编码的核心知识&#xff0c;按知识点组织&#xff0c;可作为教学或学习的参考。markdown版本已归档至【Github仓库&#xff1a;https://github.com/timerring/information-theory 】或者公众号【AIShareLab】回复 信息论 获取。 文章目录 m 序列 (最长线性反…

Git进阶系列 | 8. 用Reflog恢复丢失的提交

Git是最流行的代码版本控制系统&#xff0c;这一系列文章介绍了一些Git的高阶使用方式&#xff0c;从而帮助我们可以更好的利用Git的能力。本系列一共8篇文章&#xff0c;这是最后一篇。原文&#xff1a;Using the Reflog to Restore Lost Commits[1] “Reflog”是Git不太为人所…

常见的未授权漏洞批量检测工具

常见的未授权漏洞检测 命令行版已放出支持多线程&#xff0c;批量扫描&#xff0c;指定服务扫描&#xff0c;命令行版地址https://github.com/xk11z/unauthorized_com GUI版unauthorizedV2已更新&#xff0c;可批量ip检测导出结果 项目包含 1 、FTP 未授权访问&#xff08…