分类 qt 下的文章

一、描述

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

用于存储或组合枚举值的传统C++方法是使用整型变量。这种方法的不便之处在于根本没有类型检查,任何枚举值都可以与任何其他枚举值进行逻辑运算。

    enum Orientation
    {
        Up = 1,
        Down = 2,
        Left = 4,
        Right = 8,
    };
 
    enum Direction
    {
        horizontal = 2,
        vertical = 3,
    };

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

    Orientation::Up | Direction::horizontal;
    Orientation::Up | Orientation::Down;

第一种两个不相关的枚举值做逻辑运算没有意义,第二种运算结果是3,但Orientation中没有值是3的标识符。

Qt使用QFlags来提供类型安全性。

如果要对自己的枚举类型使用QFlags,应使用Q_DECLARE_FLAGS()和Q_DECLARE_OPERATORS_FOR_FLAGS()。

例:

  class MyClass
  {
  public:
    enum Orientation
    {
        Up = 1,
        Down = 2,
        Left = 4,
        Right = 8,
    };
    Q_DECLARE_FLAGS(Orientations, Orientation)
      ...
  };
 
  Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::Orientations)

这样为枚举Orientation创建了一个Flags:Orientations,这个Orientations的类型就是QFlags<MyClass::Orientation>。可以用Orientations对象接收逻辑运算的值了:

Orientations f = Orientation::Up | Orientation::Down;

二、Flags和元对象系统

要在元对象系统和Qt Designer中使用枚举必须加上:Q_FLAG(Orientations)

三、命名约定

一般在枚举类型后面加上s或Flag

四、使用QFlags进行逻辑运算

    enum class Orientation
    {
        Up = 1,
        Down = 2,
        Left = 4,
        Right = 8,
    };
    Q_ENUM(Orientation)        //如不使用Orientation,可省略
    Q_DECLARE_FLAGS(Orientations, Orientation)
    Q_FLAG(Orientations)
 
 
Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::Orientations)

    QMetaEnum m = QMetaEnum::fromType<Widget::Orientations>();
    qDebug()<< "key To Value:"<<m.keyToValue("Up|Down");
    qDebug()<< "value To Key:"<<m.valueToKey(Orientation::Up|Orientation::Down);
    qDebug()<< "keys To Value:"<<m.keysToValue("Up|Down");
    qDebug()<< "value To Keys:"<<m.valueToKeys(Orientation::Up|Orientation::Down)<<endl;
 
    qDebug()<< "isFlag:"<<m.isFlag();
    qDebug()<< "name:"<<m.name();
    qDebug()<< "enumName:"<<m.enumName();
    qDebug()<< "scope:"<<m.scope()<<endl;

如图,up和down再次进行或运算结果是-1,也没有对应的枚举标识。

可以据此检测逻辑运算的结果有效性:

五、枚举定义在名称空间中的情况

有几点不同:

1、需要加上Q_NAMESPACE宏,这个宏能够让命名空间具备简化的元对象能力,但不支持信号槽。

2、注册枚举的宏改成Q_ENUM_NS和Q_FLAG_NS。

3、Q_DECLARE_OPERATORS_FOR_FLAGS在名称空间中定义。

4、使用的时候前面的类名改成名称空间的名字。

namespace test
{
    Q_NAMESPACE
    enum class Orientation
    {
        Up = 1,
        Down = 2,
        Left = 4,
        Right = 8,
    };
    Q_ENUM_NS(Orientation)
    Q_DECLARE_FLAGS(Orientations, Orientation)
    Q_FLAG_NS(Orientations)
    Q_DECLARE_OPERATORS_FOR_FLAGS(Orientations)
}

六、枚举定义在实际项目中的实践

1、一个枚举变量可以代表多个bool变量的组合,这在一些复杂的控制逻辑下非常有用。一个简单的例子,客户端向服务端订阅多组不同的数据,这些数据之间有些可以同时被订阅,有些是互斥的。此时,就适合使用枚举变量来代表哪些数据已经被订阅了。此时,使用枚举类型,接口和控制逻辑都会变得简单。


// 简化的枚举类型定义
enum EDataType
{
    DT_1 = 1,
    DT_2 = 2,
    DT_3 = 4,
    DT_4 = 8,
};
Q_ENUM(EDataTypes, EDataType)

// 全局变量,保存已经订阅的数据
static EDataTypes s_data_tyes;

// 订阅
void Subscribe(EDataTypes data_types)
{
    s_data_tyes |= data_types;
}

// 反订阅
void Unsubscribe(EDataTypes data_types)
{
    s_data_types &= (0xFFFFFFFF^data_types);
}