Qt之QFlags詳解

2024年2月6日 25点热度 0人点赞

學習之前我們先補習一下枚舉和或運算的基礎

枚舉:

枚舉類型(Enum Types)是一種用戶定義的數據類型,用於表示具名的整數常量。枚舉類型可以幫助提高代碼的可讀性,使程序更易於理解。

以下是一些使用枚舉類型的典型情況:

代替魔法數值: 枚舉類型可以用於替代代碼中的魔法數值(Magic Numbers)。例如,假設你的程序中有一個表示星期的整數,你可以使用枚舉類型:

enum Weekday {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};

這樣你的代碼中就可以使用 Weekday 枚舉來表示星期,而不是使用 0 到 6 之間的數字。

有限的選項集: 當你的變量隻能有有限的一組選項時,使用枚舉類型可以提高代碼的清晰度。例如,表示顏色的枚舉:

enum Color {
    Red,
    Green,
    Blue,
    Yellow,
    // ...
};

這樣你可以使用 Color 枚舉來表示顏色,而不是使用數字或字符串。

在以上代碼中這個Weekday和Color是枚舉類型,其中Red或者Sunday是枚舉常量

枚舉類型與或運算

枚舉類型的或運算通常用於創建一個組合值,其中一個枚舉值的位被設置。這在處理一組選項或標志時非常有用。以下是一個簡單的例子:

假設有一個表示文件權限的枚舉類型:

enum FileAccess { Read = 1, Write = 2, Execute = 4 };

現在,假設你有一個文件,你想給它讀和寫的權限:

FileAccess myFilePermissions = Read | Write;

在這裡,| 是按位或運算符,用於將 Read 和 Write 枚舉值的對應位進行組合。現在,myFilePermissions 的值是 Read | Write 的組合,它的二進制表示為11;所以值就是十進制的3

計算過程

關鍵詞復習:組合值(類型枚舉的組合)(或運算)這種邏輯運算有時候也叫做位掩碼(bitmasks)

進入正題QFlags:

首先說一下普通枚舉得缺點:

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的標識符。

在Qt6中c 開發指南中是這樣介紹QFlags的:

QFlags<Enum>是一個模板類,其中Enum是枚舉類型,QFlags用於定義枚舉值的或運算組合,在Qt中經常用到 QFlags 類。例如,QLabel 有一個alignment 屬性,其讀寫函數分別定義如下:

Qt::Alignment alignment()
void setAlignment(Ot::Alignment)

alignment屬性值是Qt:Alignment類型Qt幫助文檔中顯示的Qt::Alignment信息有如下表示

enum Qt::AlignmentFlag  //枚舉類型
flags Qt::Alignment     //標志類型

第一行代碼翻譯一下就是Qt命名空間下的有一個變量名字叫做AlignmentFlag他是枚舉類型

【粉絲福利】Qt開發學習資料包、大廠面試題、項目視頻、學習路線,包括(Qt C 基礎,數據庫編程,Qt項目實戰、Qt框架、QML、Opencv、qt線程等等)有需要的可以進企鵝裙937552610領取哦~

這表示Qt::Alignment是QFlags<Qt::AlignmentFlag>類型,但是Qt中並沒有定義實際的類型Qt::Alignment,也就是不存在如下的定義:

這樣的定義實際不存在

typedef QFlags<Qt::AlignmentFlag> Qt::Alignment;

Qt::AlignmentFlag 是枚舉類型,其有一些枚舉常量。

如:

詳見Qt文檔。

Ot::Alignment是一個或多個Qt:AlignmentFlag類型枚舉值的組合,是一種特性標志。

即Alignment可以是 AlignLeft | AlignRight

也可以是 AlignHCenter | AlignLeft所以我們把Qt::Alignment稱為枚舉類型Qt::AlignmentFlag的標志類型。

給窗口上的OLabel組件label 設置對齊方式,可以使用如下的代碼

ui->label->setAlignment(Qt::AlignLeft lQt::AlignVCenter);

這實際上是創建了一個Qt::Alignment類型的臨時變量,相當於如下的代碼:

QFlags<Qt::AlignmentFlag> flags = Qt::AlignLeft | Qt::AlignVCenter;
ui->label->setAlignment(flags);

看這段代碼並有沒有寫Qt::Alignment = Qt::AlignLeft | Qt::AlignVCenter;

也可以看出實際並沒有Qt::Alignment,他隻是一個標志。

QFlags 類支持或、與、異或等位運算,所以也可以這樣寫代碼\

QFlags<Qt::AlignmentFlag> flags= ui->label->alignment();//獲取alignment 屬性值
flags = flags | Qt::AlignVCenter;//增加垂直對齊
u1->label->setAlignment(flags);//設置alignment 屬性值

這裡主要是要區分幫助文檔中enum Qt:AlignmentFlag 和flags Qt::Alignment的意義,不要把QLabel的setAlignment()函數的輸入參數認為是枚舉類型,它實際上是標志類型。

QFlags類有一個函數testFlag()可以測試某個枚舉值是否包含在此標志變量中,例如:

//獲取alignment 屬性值//是否包含
QFlags<Ot;:AlignmentFlag> flags= ui->label->alignment();
bool isLeft = flags.testFlag(Qt::AlignLeft);

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;