Qt中的测试 枚举与 QFlags详解
传统的 C++ 编程中,通常使用整数来保存 enum 的逻辑运算结果 (与、或、非、异或等),在进行逻辑运算的时候没有进行类型检查,一个枚举类型可以和其他的枚举类型进行逻辑运算,运算的结果可以直接传递给接收参数为整数的函数。
Qt 中,模板类 QFlags<Enum>
提供了类型安全的方式保存 enum 的逻辑运算结果解决上面的这几个问题,这种方式在 Qt 里很常见,例如设置 QLabel 对齐方式的函数是 QLabel::setAlignment(Qt::Alignment)
(typedef QFlags<Qt::AlignmentFlag> Qt::Alignment
),这就意味着传给 setAlignment 的参数只能是枚举 Qt::AlignmentFlag
的变量、它们的逻辑运算结果或者 0,如果传入其他的枚举类型或者非 0 值,编译时就会报错:
label->setAlignment(0);
label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
label->setAlignment(Qt::WA_Hover); // Error: 编译时报错
想要把我们定义的枚举类型和 QFlags 一起使用,需要用到两个宏:
Q_DECLARE_FLAGS(Flags, Enum)
:- Enum 是已经定义好的枚举类型
- 展开的结果为
typedef QFlags<Enum> Flags
Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)
:- Flags 就是类型
QFlags<Enum>
- 给 Flags 定义了运算符
|
,使得 Enum 和 Enum,Enum 和 Flags 能够使用或运算符|
,结果为 Flags
- Flags 就是类型
使用 QFlags 时需要留意以下几点:
- QFlags 其实就是用于位操作,设置它保存的数值的某一位为 1 或者为 0,所以和 QFlags 一起使用的枚举类型,其变量的值需要是 2 的 n 次方,即 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, …,它们的特点是其二进制位中只有一位是 1,其他位全部为 0,这样每一个枚举值只会和 QFlags 中的某一个位对应,不会出现交叉的情况
- 调用函数
QFlags::setFlag(Enum flag, bool on = true)
,on 为 true 时设置 flag 对应的位为 1,on 为 false 时设置 flag 对应的位为 0,设置 flag 对应的位为 1 还可以使用运算符|
- 调用函数
QFlags::testFlag(Enum flag)
测试 flag 对应的位是否为 1 - 整数转为 QFlags: 把整数作为 QFlags 构造函数的参数创建一个 QFlags 变量
- QFlags 转为整数: 调用
int(flags)
把 QFlags 变量转换为整数值
下面就演示一下怎么使用 QFlags:
// Flag 的变量值是 2^n, 每个值的二进制只有一个位是 1,其他全为 0
enum class Flag {Js = 0x01, // 1 : 0000 0001Go = 0x02, // 2 : 0000 0010Cpp = 0x04, // 4 : 0000 0100Php = 0x08, // 8 : 0000 1000Java = 0x10, // 16 : 0001 0000Scala = 0x20, // 32 : 0010 0000};
Q_DECLARE_FLAGS(Flags, Flag)
Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) // 使得 Flag 和 Flag,Flag 和 Flags 能够使用或运算符 |,结果为 Flagsint main() {Flags flags(0x08); // int to Flagsflags |= Flag::Js; // 添加 Jsflags |= Flag::Go; // 添加 Goflags.setFlag(Flag::Cpp, true); // 添加 Cppflags.setFlag(Flag::Cpp, false); // 删除 CppqDebug() << flags; // 输出: QFlags(0x1|0x2|0x8)qDebug() << flags.testFlag(Flag::Js); // 输出: trueqDebug() << flags.testFlag(Flag::Cpp); // 输出: falseqDebug() << int(flags); // 输出: 11 (Flags to int)flags = Flag::Java | Flag::Scala; // 使用 | 同时设置多个 flagqDebug() << flags; // 输出: QFlags(0x10|0x20)// flags = Flag::Java | Qt::AlignLeft; // Error: no viable overloaded =return 0;
}
在日常开发中,权限也可以使用 QFlags 来实现,下面只演示 3 种权限的使用,实际开发中根据具体业务需求修改枚举类型 Permission 的变量即可:
#include <QMap>
#include <QStringList>// 权限
enum class Permission {Readable = 0x01,Writable = 0x02,Excutable = 0x04,
};Q_DECLARE_FLAGS(Permissions, Permission)
Q_DECLARE_OPERATORS_FOR_FLAGS(Permissions)// 权限的值和其对应的 label 的 map
QMap<Permission, QString> PermissionLabelMap {{ Permission::Readable, "可读" },{ Permission::Writable, "可写" },{ Permission::Excutable, "可执行" },
};// 用户
class User {
public:User(const QString &username, int psValue) {this->username = username;this->ps = Permissions(psValue);}bool hasPermission(Permission p) const {return ps.testFlag(p);}void addPermission(Permission p) {ps.setFlag(p, true);}void addPermissions(Permissions ps) {this->ps |= ps;}void removePermission(Permission p) {ps.setFlag(p, false);}void removePermissions(Permissions ps) {this->ps &= Permissions(~(int(ps)));}Permissions getPermissions() const {return ps;}QStringList getPermissionLabels() const {QStringList labels;for (auto i = PermissionLabelMap.cbegin(); i != PermissionLabelMap.cend(); ++i) {if (ps.testFlag(i.key())) {labels << i.value();}}return labels;}private:Permissions ps;QString username;
};int main() {User user("Bob", 0);user.addPermissions(Permission::Readable | Permission::Excutable);qDebug() << user.getPermissions(); // 输出: QFlags(0x1|0x4)qDebug() << user.getPermissionLabels(); // 输出: ("可读", "可执行")qDebug() << user.hasPermission(Permission::Readable); // 输出: trueqDebug() << user.hasPermission(Permission::Writable); // 输出: falseuser.addPermission(Permission::Writable);qDebug() << user.getPermissions(); // 输出: QFlags(0x1|0x2|0x4)qDebug() << int(user.getPermissions()); // 输出: 7user.removePermissions(Permission::Readable | Permission::Excutable);qDebug() << user.getPermissionLabels(); // 输出: ("可写")return 0;
}
又例如:
class CComGeneralTableWidget : public QTableWidget
{Q_OBJECTpublic:CComGeneralTableWidget(QWidget *parent = Q_NULLPTR);~CComGeneralTableWidget();/* 显示属性枚举(注意:id、设计id、可见性、显示名是所有元件都有且必须在属性对话框中显示的,这里就不再列出了,这里仅仅是列出有些元件需要显示的,有些元件不需要显示的,通过枚举值来控制哪些显示,哪些不显示),枚举值必须为0、2的N次方(N >= 0)*/enum class EmShowProp{eNotShowAllProp = 0, // 画笔颜色、画笔宽度、画刷颜色、线型、旋转信息都不显示eShowRotateProp = 1, // 显示旋转信息eShowPenColorProp = 2, // 显示画笔颜色eShowPenWidthProp = 4, // 显示画笔宽度eShowBrushColorProp = 8, // 显示画刷颜色eShowLineTypeProp = 16, // 显示线型// 显示所有eShowAllProp = eShowRotateProp | eShowPenColorProp | eShowPenWidthProp | eShowBrushColorProp | eShowLineTypeProp};Q_DECLARE_FLAGS(EmShowProps, EmShowProp)....// 类的其它代码
private:EmShowProps m_eShowProp{ EmShowProp::eShowAllProp };
};Q_DECLARE_OPERATORS_FOR_FLAGS(CComGeneralTableWidget::EmShowProps)
注意:通过上述Q_DECLARE_FLAGS声明后, 定义枚举不再是EmShowProp(最原始的用enum声明的、宏的第二个参数)而是 EmShowProps(宏的第一个参数),如果还用enum声明的枚举名定义枚举变量,则会报如下错误:
error C2228: “.testFlag”的左边必须有类/结构/联合
Qt中的测试 枚举与 QFlags详解相关推荐
- (17)System Verilog枚举类型enum详解
(17)System Verilog枚举类型enum详解 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog枚举类型enum详解 5)结语 ...
- QT QSpinBox 整数计数器控件 使用详解
本文详细的介绍了QSpinBox控件的各种操作,例如:获取数值.设置前后缀.设置最大/小值.进制转换.关联信号槽.优化信号.QSS优化.文件源码.样式表 .效果:可以设置背景.边框.向上按钮.向下按钮 ...
- yii mysql 事务处理_Yii2中事务的使用实例代码详解
前言 一般我们做业务逻辑,都不会仅仅关联一个数据表,所以,会面临事务问题. 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全 ...
- Python中的__name__和__main__含义详解
背景 在写Python代码和看Python代码时,我们常常可以看到这样的代码: ? 1 2 3 4 5 def main(): ...... if __name__ == "__ma ...
- Java6.0中Comparable接口与Comparator接口详解
Java6.0中Comparable接口与Comparator接口详解 说到现在,读者应该对Comparable接口有了大概的了解,但是为什么又要有一个Comparator接口呢?难道Java的开发者 ...
- 教程-Delphi中Spcomm使用属性及用法详解
Delphi中Spcomm使用属性及用法详解 Delphi是一种具有 功能强大.简便易用和代码执行速度快等优点的可视化快速应用开发工具,它在构架企业信息系统方面发挥着越来越重要的作用,许多程序员愿意选 ...
- java 泛型详解、Java中的泛型方法、 java泛型详解
本文参考java 泛型详解.Java中的泛型方法. java泛型详解 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用. 什么是泛型?为什么要使用泛型? 泛型,即& ...
- java break 在if 中使用_java中使用国密SM4算法详解
前言 上次总结了一下加密算法的分类(加密算法有集中形式,各有什么不同?),现在我们用java语言实现一下SM4:无线局域网标准的分组数据算法.对称加密,密钥长度和分组长度均为128位. ps:我们既可 ...
- python支持向量机回归_Python中支持向量机SVM的使用方法详解
除了在Matlab中使用PRTools工具箱中的svm算法,Python中一样可以使用支持向量机做分类.因为Python中的sklearn库也集成了SVM算法,本文的运行环境是Pycharm. 一.导 ...
最新文章
- linux更改文件夹权限_Linux 一些重点知识,整理的很全面,有必要收藏
- 在2020年到来之前,你应该知道的10大科技趋势预测
- doT.js-doT模板方便快捷的组织页面DOM
- php session不生效_php 验证session无效问题解决办法
- proc_open 命令包含“有小问题
- PMcaff课堂:10年经验的产品大咖眼中的社交产品是这样的
- leetcode 558. Logical OR of Two Binary Grids Represented as Quad-Trees | 558. 四叉树交集(分治法)
- 代理模式和动态代理模式_代理模式介绍
- JAVA环境变量安装
- 安装运行jupyter notebook时报错:ModuleNotFoundError: No module named 'prompt_toolkit.formatted_text'...
- 有趣的问题:C的表达式x == x,何时为假?!
- HPnbsp;Jetdirectnbsp;打印服务器配置
- 链家混三个月底薪_应届毕业生入职链家,到离职
- 提交模式窗口后,刷新父窗口数据+获取frameset中各模块中数据
- css给网页添加 黑白滤镜
- strtok函数及其实现
- 根据GPS经纬度判断当前所属的市区
- 这个季节,想到了什么
- png 微软ppt 透明度,教你一招永久搞定PPT导出高清图片的小技巧
- matlab安装及使用
热门文章
- 人才空缺4600万!大厂优先录用,这个职业今年火遍全网
- 华硕服务器显示模块,华硕远程管理模块 ASMB4-iKVM 华硕服务器主板专用 现货 IPMI...
- Natasha V1.3.6.0 的升级日志
- Qt在控制台输出中文的解决办法(转载)
- JAVA中的设计模式三(策略模式)
- cxf返回的报文,命名空间无前缀
- Win7 x64 PL/SQL 连接 Oralce 提示 Could not initialize %ORACLE_HOME%\bin\oci.dll
- 山寨今日头条的标题title效果
- 好书推荐之《活着》 隐私策略(Privacy policy)
- 2.6.24及以上版本内核裁剪后启动黑屏的解决办法