[QT] Enumerate commonly used macros (Q_ENUM, Q_FLAG, Q_DECLARE_FLAGS, Q_DECLARE_OPERATORS_FOR_FLAGS)

1. Q_ENUM macro and QMetaEnum class

1.1 The role of the Q_ENUM macro

  1. The macro Q_ENUM registers an enumeration type with the meta-object system

1.2 Notes on using Q_ENUM

  1. Before using Q_ENUM, the Q_OBJECT or Q_GADGET macro must be declared in the class.
  2. Q_ENUM (enumeration type) must be placed after the enumeration declaration, and the compiler will report an error if it is placed in front.
  3. The Q_ENUM macro was introduced from Qt5.5. Please use the Q_ENUMS macro in previous versions of Qt, but the Q_ENUMS macro does not support the QMetaEnum::fromType() function (this is why Q_ENUMS is deprecated)

1.3 When writing code related to enumeration, we may encounter this situation: what should we do if we need to use the enumeration string?

At this time, you need to use the Q_ENUM macro and the QMetaEnum class.
For enumerations declared with Q_ENUM, their QMetaEnum is registered in an external QMetaObject. Before version 5.5, you can use QMetaObject to get QMetaEnum.

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

You can also use the static function QMetaEnum::fromType() to get QMetaEnum.

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

Through the QMetaEnum object, you can get some information about the enumeration and the conversion between the enumeration type and the string type.

1.4 The following is a simple code to illustrate the function of 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() {
    
    }

insert image description here
需要知道的是:QMetaEnum will subscript all enumerations, starting from 0.
       QMetaEnum saves and retrieves enumerations by way of key and value.
The above code can see the enumeration declared by Q_ENUM, and many information of the enumeration can be obtained through the QMetaEnum object. For example, the name of the enumeration, the number of enumerations, the key and value of the enumeration, and so on.

2. Q_FLAG macro

2.1 The role of the Q_FLAG macro

The macro Q_FLAG registers a single flag type with the meta-object system.
For enumerations declared with the macro Q_FLAG, the enumeration values ​​can be used as flags and combined using the bitwise OR operator (|).

If a bit-OR operation is performed, the enumeration value in the above code cannot be defined in that way, because the bit-or operation is an "OR operation" based on binary bits, and the definition of its enumeration value needs to be defined in terms of bits (that is, different enumerations Each bit of its binary value is different). For example:

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

2.2 The function of Q_DECLARE_FLAGS() macro

The Q_DECLARE_FLAGS(Flags, Enum) macro expands to:

 typedef QFlags<Enum> Flags;

QFlags<Enum> is a template class, where Enum is an enumeration type, and QFlags is used to store the combination of enumeration values.

In traditional C++ programming, integers are usually used to store the logical operation results of enum (AND, OR, NOT, XOR, etc.), and no type checking is performed when logical operations are performed. An enumeration type can be compared with other enumeration types Perform logical operations, and the results of the operations can be directly passed to functions that receive integers as parameters.

Let's see an example:

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

The compiler will not report an error for this operation:

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

For the above problem, how should we solve it?
In Qt, the template class QFlags<Enum> provides a type-safe way to save the logical operation results of enum to solve the above problems.

This method is very common in Qt. For example, the function to set the alignment of QLabel is QLabel::setAlignment(Qt::Alignment) (typedef QFlagsQt::AlignmentFlag Qt::Alignment), which means that the parameters passed to setAlignment can only It is the variables of the enumeration Qt::AlignmentFlag, their logical operation results or 0, if other enumeration types or non-zero values ​​are passed in, an error will be reported at compile time, for example:

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

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

In short, the Q_DECLARE_FLAGS(Flags, Enum) macro redefines the ordinary structure Enum into a safe structure Flags that can freely perform bit OR operations.

2.3 The function of Q_DECLARE_OPERATORS_FOR_FLAGS() macro

  1. Q_DECLARE_OPERATORS_FOR_FLAGS(Flags) gives Flags a global operator "|". Without this macro statement, the result of AND operation between Flags quantities will be an int value instead of Flags value . This is especially important.
  2. Q_DECLARE_OPERATORS_FOR_FLAGS must be defined outside the class.
  3. Q_DECLARE_OPERATORS_FOR_FLAGS only provides "or" operation, not "and" and "not" operation.
  4. Both Q_DECLARE_FLAGS and Q_DECLARE_OPERATORS_FOR_FLAGS have nothing to do with the meta-object system and can be used independently of Q_FLAG. In fact, these two macros already existed in Qt4 (not sure if they existed earlier), and Q_FLAG was only added in Qt5.5.

2.4 Demo code

#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() {
    
    }

insert image description here

Guess you like

Origin blog.csdn.net/WL0616/article/details/131376253