日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他

發布時間:2023/12/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Qt中的枚舉變量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他

  • 前言
  • Q_ENUM的使用
  • Q_FLAG的引入解決什么問題?
  • Q_NAMESPACE,Q_ENUM_NS和Q_FLAG_NS
  • 新舊對比
  • 結語

前言
之前做一個比較大工程,核心數據里面有很多是枚舉變量,需要頻繁地使用枚舉量到字符串和字符串到枚舉量的操作,為了實現這些操作,我把每個枚舉類型后面都附加了兩個類似Enum_to_String()和String_to_Enum()的函數,程序顯得很臃腫。這時候就非常羨慕C#或者java等兄弟語言,內核內置了枚舉量和字符串轉換的方法。
最近讀Qt文檔時偶然間發現,Qt內核其實已經提供了這個轉換機制,使得我們能用很少的代碼完成枚舉量和字符串的轉換,甚至還能實現其他更酷更強大的功能,下面我們就來看看如何使用Qt的這個功能。
簡單來講,Qt還是使用一組宏命令來完成枚舉量擴展功能的(正如Qt的其他核心機制一樣),這些宏包括Q_ENUM,Q_FLAG,Q_ENUM_NS,Q_FLAG_NS,Q_DECLARE_FLAGS,Q_DECLARE_OPERATORS_FOR_FLAGS,
這些宏的實現原理和如何展開如何注冊到Qt內核均不在本文的講解范圍,本文只講應用。

Q_ENUM的使用
首先講解最簡單明了的宏Q_ENUM,先看代碼:
?

#include <QObject>class MyEnum : public QObject {Q_OBJECT public:explicit MyEnum(QObject *parent = nullptr);enum Priority{High = 1,Low = 2,VeryHigh = 3,VeryLow = 4};Q_ENUM(Priority) };

這就是在類中定義了一個普通的枚舉變量之后,額外加入了Q_ENUM(枚舉類型名)這樣的一個宏語句,那么加入了這個Qt引入的宏語句后,我們能得到什么收益呢??

qDebug()<< MyEnum::High<< MyEnum::Low; //qDebug()可以直接打印出枚舉類值的字符串值 QMetaEnum m = QMetaEnum::fromType<MyEnum::Priority>(); //since Qt5.5 qDebug()<< "keyToValue:"<< m.keyToValue("VeryHigh"); qDebug()<< "valueToKey:"<< m.valueToKey(MyEnum::VeryHigh); qDebug()<< "keyCount:"<< m.keyCount(); qDebug() << m.scope() << m.name();

輸出結果如下:

注意:如果沒有用Q_ENUM(Priority),則會報如下錯誤:

且此時qDebug() << MyEnum::High << MyEnum::Low;? ? ? 輸出的是枚舉類型表示的數值即1和2而不是字符串。??m.scope()返回枚舉所在類名,本類中的枚舉在MyEnum類的內部定義,所以返回的是MyEnum,m.name()返回是枚舉名,本例的枚舉名是Priority,如果將枚舉定義放到內的外部,則m.scope()返回空。另外對于Qt的Qt's Property System、Meta-Object System默認是不支持枚舉類型的,即如下代碼:

Q_PROPERTY(EnFlowOrient floworient READ flowOrient WRITE setFlowOrient STORED true DESIGNABLE true)

中的EnFlowOrient枚舉定義如下:

// 油液流動的方向enum class EnFlowOrient{eRightOrDownFlow, eLeftOrUpFlow, };

?默認是不支持的,要使其支持枚舉,也必須用用Q_ENUM(EnFlowOrient);聲明且枚舉必須放在類內部聲明且必須是public才行。

可見,使用Q_ENUM注冊過的枚舉類型,可以不加修飾直接被qDebug()打印出來,另外通過靜態函數QMetaEnum::fromType()可以獲得一個QMetaEnum 對象,以此作為中介,能夠輕松完成枚舉量和字符串之間的相互轉化。這一點恐怕是引入Q_ENUM機制最直接的好處。
除此以外,QMetaEnum還提供了一個內部的索引,從1開始給每個枚舉量按自然數順序編號(注意和枚舉量本身的數值是兩回事),提供了int value(int index) 和const char *key(int index)
兩個便捷函數分別返回枚舉量對應的數值和枚舉量對應的字符串,配合keyCount() 函數可以實現枚舉量的遍歷:
?

qDebug()<<m.name()<<":"; for (int i = 0; i < m.keyCount(); ++i) {qDebug()<<m.key(i)<<m.value(i); }

輸出:

Priority : High 1 Low 2 VeryHigh 4 VeryLow 8

其中name()函數返回枚舉類型名字。
Q_ENUM使用起來很很簡單,對不對?但是還是有幾個注意事項需要說明:

Q_ENUM只能在使用了Q_OBJECT或者Q_GADGET的類中,類可以不繼承自QObject,但一定要有上面兩個宏之一(Q_GADGET是Q_OBJECT的簡化版,提供元對象的一部分功能,但不支持信號槽);
Q_ENUM宏只能放置于所包含的結構體定義之后,放在前面編譯器會報錯,結構體定義和Q_ENUM宏之間可以插入其他語句,但不建議這樣做;
一個類頭文件中可以定義多個Q_ENUM加持的結構體,結構體和Q_ENUM是一一對應的關系;
Q_ENUM加持的結構體必須是公有的;
Q_ENUM宏引入自Qt5.5版本,之前版本的Qt請使用Q_ENUMS宏,但Q_ENUMS宏不支持QMetaEnum::fromType()函數(這也是Q_ENUMS被棄用的原因)。

Q_FLAG的引入解決什么問題?

除了Q_ENUM,Qt中還有另一個類似的宏——Q_FLAG,著力彌補C++中結構體無法組合使用,和缺乏類型檢查的缺點,怎么理解呢?我們看一個例子:
在經典C++中,如果我們要定義一個表示方位的結構體:

enum Orientation { Up = 1, Down = 2, Left = 4, Right = 8 };

注意這里枚舉值被定義成等比數列,這個技巧給使用"|“操作符擴展留下了空間,比如,左上可以用Up | Left來簡單表示,但是這里也帶來了一個問題,Up | Left值是一個整型,并不在枚舉結構Orientation中,如果函數使用Orientation作為自變量,編譯器是無法通過的,為此往往把函數自變量類型改為整型,但因此也就丟掉了類型檢查,輸入量有可能是其他無意義的整型量,在運行時帶來錯誤。
Qt引入QFlags類,配合一組宏命令完美地解決了這個問題。
QFlags是一個簡單的類,可以裝入一個枚舉量,并重載了與或非等運算符,使得枚舉量能進行與或非運算,且運算結果還是一個QFlags包裝的枚舉量。一個普通的枚舉類型包裝成QFlags型,需要使用Q_DECLARE_FLAGS宏,在全局任意地方使用”|"操作符計算自定義的枚舉量,需要使用Q_DECLARE_OPERATORS_FOR_FLAGS宏。
再看一段代碼:
?

class MyEnum : public QObject {Q_OBJECT public:explicit MyEnum(QObject *parent = nullptr);enum Orientation{Up = 1,Down = 2,Left = 4,Right = 8,};Q_ENUM(Orientation) //如不使用Orientation,可省略Q_DECLARE_FLAGS(OrientationFlags, Orientation)Q_FLAG(OrientationFlags) };Q_DECLARE_OPERATORS_FOR_FLAGS(MyEnum::OrientationFlags)

?上面這段代碼展示了使用Q_FLAG包裝枚舉定義的方法,代碼中Q_DECLARE_FLAGS(Flags, Enum)實際上被展開成typedef QFlags< Enum > Flags,所以Q_DECLARE_FLAGS實際上是QFlags的定義式,之后才能使用Q_FLAG(Flags)把定義的Flags注冊到元對象系統。Q_FLAG完成的功能和Q_ENUM是類似的,使得枚舉量可以被QMetaEnum::fromType()調用。
看一下使用代碼:
?

qDebug()<<(MyEnum::Up|MyEnum::Down); QMetaEnum m = QMetaEnum::fromType<MyEnum::OrientationFlags>(); //since Qt5.5 qDebug()<< "keyToValue:"<<m.keyToValue("Up|Down"); qDebug()<< "valueToKey:"<<m.valueToKey(Up|Down); qDebug()<< "keysToValue:"<<m.keysToValue("Up|Down"); qDebug()<< "valueToKeys:"<<m.valueToKeys(Up|Down)<<endl;qDebug()<< "isFlag:"<<m.isFlag(); qDebug()<< "name:"<<m.name(); qDebug()<< "enumName:"<<m.enumName(); //since Qt5.12 qDebug()<< "scope:"<<m.scope()<<endl;

執行結果:

QFlags<MyEnum::Orientation>(Up|Down) keyToValue: -1 valueToKey: keysToValue: 3 valueToKeys: "Up|Down" isFlag: true name: OrientationFlags enumName: Orientation scope: MyEnum

?可以看到,經過Q_FLAG包裝之后,QMetaEnum具有了操作復合枚舉量的能力,注意這時應當使用keysToValue()和valueToKeys()函數,取代之前的keyToValue()和valueToKey()函數。另外,isFlag()函數返回值變成了true,name()和enumName()分別返回Q_FLAG包裝后和包裝前的結構名。
實際上此時類中是存在兩個結構體的,如果在定義時加上了Q_ENUM(Orientation),則Orientation和OrientationFlags都能被QMetaEnum識別并使用,只不過通常我們只關注Q_FLAG包裝后的結構體。
這樣我們順便明白了Qt官方定義的許多枚舉結構都是成對出現的原因,比如
?

enum Qt::AlignmentFlag flags Qt::Alignment enum Qt::MatchFlag flags Qt::MatchFlags enum Qt::MouseButton flags Qt::MouseButtons

再總結下Q_FLAG以及Q_DECLARE_FLAGS、Q_DECLARE_OPERATORS_FOR_FLAGS使用的要點吧:

Q_DECLARE_FLAGS(Flags, Enum)宏將普通結構體Enum重新定義成了一個可以自由進行與或非操作的安全的結構體Flags。Q_DECLARE_FLAG出現在Enum定義之后,且定義之后Enum和Flags是同時存在的;
Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)賦予了Flags一個全局操作符“|”,沒有這個宏語句,Flags量之間進行與操作后的結果將是一個int值,而不是Flags值。Q_DECLARE_OPERATORS_FOR_FLAGS應當定義在類外;
Q_DECLARE_OPERATORS_FOR_FLAGS只提供了“或”操作,沒有提供“與”“非”操作;
Q_DECLARE_FLAGS和Q_DECLARE_OPERATORS_FOR_FLAGS都是和元對象系統無關的,可以脫離Q_FLAG單獨使用,事實上這兩個宏在Qt4就已經存在(不確定更早是否存在),而Q_FLAG是在Qt5.5版本才加入的;
如果在我們的程序中不需要枚舉變量的組合擴展,那么只用簡單的Q_ENUM就好了。
Q_NAMESPACE,Q_ENUM_NS和Q_FLAG_NS
在Qt5.8之后,Qt引入了Q_NAMESPACE宏,這個宏能夠讓命名空間具備簡化的元對象能力,但不支持信號槽(類似類里的Q_GADGET)。
在使用了Q_NAMESPACE的命名空間中,可以使用Q_ENUM_NS和Q_FLAG_NS,實現類中Q_ENUM和Q_FLAG的功能。
看一個例子:

namespace MyNamespace { Q_NAMESPACE enum Priority {High = 1,Low = 2,VeryHigh = 4,VeryLow = 8, }; Q_ENUM_NS(Priority) //如不使用Priority,可省略 Q_DECLARE_FLAGS(Prioritys, Priority) Q_FLAG_NS(Prioritys) Q_DECLARE_OPERATORS_FOR_FLAGS(Prioritys) }

?命名空間中Q_ENUM_NS和Q_FLAG_NS的使用和之前相類似,不再贅述。Q_DECLARE_OPERATORS_FOR_FLAGS則需要定義在命名空間之內。
使用代碼:

using namespace MyNamespace; qDebug()<<(High|Low); QMetaEnum m = QMetaEnum::fromType<MyNamespace::Prioritys>(); //since Qt5.5 qDebug()<< "keyToValue:"<<m.keyToValue("High|Low"); qDebug()<< "valueToKey:"<<m.valueToKey(High|Low);qDebug()<< "keysToValue:"<<m.keysToValue("High|Low"); qDebug()<< "valueToKeys:"<<m.valueToKeys(High|Low)<<endl;qDebug()<< "isFlag:"<<m.isFlag(); qDebug()<< "name:"<<m.name(); qDebug()<< "enumName:"<<m.enumName(); //since Qt5.12 qDebug()<< "scope:"<<m.scope()<<endl;

運行結果:

QFlags<MyNamespace::Priority>(High|Low) keyToValue: -1 valueToKey: keysToValue: 3 valueToKeys: "High|Low" isFlag: true name: Prioritys enumName: Priority scope: MyNamespace

可以看到,從定義到使用,和之前Q_FLAG幾乎一模一樣。
在命名空間中使用Q_ENUM_NS或者Q_FLAG_NS,能讓枚舉結構體定義不再局限在類里,使我們有更多的選擇。另外,在今后Qt的發展中,相信Q_NAMESPACE能帶來更多的功能,我們拭目以待。

新舊對比
Qt一直是一個發展的框架,不斷有新特性加入,使得Qt變得更易用。
本文介紹的內容都是在Qt5.5版本以后才引入的,Q_NAMESPACE的內容甚至要到Qt5.8版本才引入,在之前Qt中也存在著枚舉量的擴展封裝——主要是Q_ENUMS和Q_FLAGS,這套系統雖然已經不建議使用,但是為了兼容性,還是予以保留。我們看看之前的系統如何使用的:
枚舉量定義基本一致,就是Q_ENUMS(Enum)宏放到定義之前,代碼從略。
使用上:

QMetaObject object = MyEnum::staticMetaObject; //before Qt5.5 int index = object.indexOfEnumerator("Orientation"); QMetaEnum m = object.enumerator(index);

對比改進后的:

QMetaEnum m = QMetaEnum::fromType<MyEnum::Orientation>(); //since Qt5.5

不僅僅是3行代碼簡化成1行,更重要的是Qt程序員終于不用再顯式調用元對象QMetaObject了。改進的代碼元對象機制同樣在起著作用,但卻變得更加隱蔽,更加沉默,使得程序員可以把精力更多放到功能的實現上,這大概就是Qt發展的方向。

結語
很多Qt程序員喜歡用舊版本編程,但是我是堅定的新版本擁躉,在給程序編寫帶來便利的同時,還能滿足自己的好奇心,何樂而不為呢?
?
原文鏈接:https://blog.csdn.net/qq_36179504/article/details/100895133

總結

以上是生活随笔為你收集整理的Qt中的枚举变量,Q_ENUM,Q_FLAG,Q_NAMESPACE,Q_ENUM_NS,Q_FLAG_NS以及其他的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 97视频久久 | 国产欧美精品一区二区三区 | 久久手机视频 | 丰满少妇麻豆av苏语棠 | 在线亚洲不卡 | 超碰日韩在线 | a天堂av| 亚洲免费天堂 | av加勒比| 亚洲综合激情五月久久 | 色在线免费视频 | 成人激情久久 | 91亚洲国产成人精品一区 | 涩色网| 上海贵妇尝试黑人洋吊 | 婷婷久久亚洲 | 亚洲在线视频播放 | 欧美黄色大片网站 | 凸凹人妻人人澡人人添 | 97久久免费视频 | 台湾佬久久 | 特级淫片裸体免费看冫 | 午夜亚洲成人 | 欧美日韩视频一区二区 | 日本性爱视频在线观看 | 国产精品一线天粉嫩av | 亚洲精品国产精品乱码在线观看 | 男女福利视频 | 中文字幕一区二区三区四区不卡 | 国产精品最新 | 久久国产精品久久久久 | 特级丰满少妇一级aaaa爱毛片 | 日本美女一区二区 | 国产最新自拍视频 | 国产区视频在线 | 少妇天堂网 | 亚洲伦理中文字幕 | 毛片免费一区二区三区 | 天天看夜夜操 | 森泽佳奈av | 欧美高清 | 777精品视频 | 午夜天堂精品 | 亚洲永久无码精品一区二区 | 中文字幕日韩欧美在线 | 久久天天躁狠狠躁夜夜躁2014 | 国产亚洲无 | 成人毛片视频免费看 | 无码精品一区二区三区AV | 成人一级影片 | 色噜噜狠狠一区二区 | 欧美不卡一区 | 日本妇女毛茸茸 | 亚州色图欧美色图| 中文字幕黑丝 | 美女赤身免费网站 | 特级毛片爽www免费版 | 超级黄色片 | 亚洲AV无码精品国产 | 国产精品天天干 | 日韩电影在线观看一区 | 欧美国产日韩视频 | 欧美一级网 | 免费成年人视频 | 日韩一级特黄 | 国产精品一二区在线观看 | 明星双性精跪趴灌满h | 久久黄页| 欧美三级韩国三级日本三斤 | 欧美黄色小说 | 黄色片视频免费看 | 日本三级黄色录像 | 免费毛片一区二区三区 | 黄色激情在线观看 | 一区二区三区高清不卡 | 国产女主播在线一区二区 | 男人的天堂一区 | 三级影片在线免费观看 | 色爽爽一区二区三区 | 国产特级毛片aaaaaa | 哺乳期av | 先锋成人 | 色女人天堂 | 综合久久91 | 久久国产精品久久精品国产 | 日本国产三级xxxxxx | 精品久久久久中文慕人妻 | 九色91丨porny丨丝袜 | 美梦视频大全在线观看高清 | 男人av在线 | 国产无套精品一区二区 | 欧美在线一区二区视频 | 黄色录象片 | 日日噜噜噜夜夜爽爽狠狠 | 视频区图片区小说区 | 激情综合五月网 | av不卡免费在线 | 亚洲性综合 | 成年人视频网站 |