Qt提供了一個絕妙的屬性系統。跟那些由編譯器提供的屬性差不多。然而,作為一個獨立於編譯器和平台的庫,Qt不依賴於非標准的編譯特性,比如__property 或[property]。Qt可以在任何平台上的標准編譯器下編譯。Qt屬性系統基於元數據對象系統--就是那個提供了對象內置信號和槽通訊機制的家伙。
Q_PROPERTY()是一個宏,用來在一個類中聲明一個屬性property,由於該宏是qt特有的,需要用moc進行編譯,故必須繼承於QObject類。
1 Q_PROPERTY(type name 2 READ getFunction 3 [WRITE setFunction] 4 [RESET resetFunction] 5 [NOTIFY notifySignal] 6 [DESIGNABLE bool] 7 [SCRIPTABLE bool] 8 [STORED bool] 9 [USER bool] 10 [CONSTANT] 11 [FINAL])
下面是一些典型的聲明屬性的示例:
1 Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue) 2 Q_PROPERTY(bool animation READ getAnimation WRITE setAnimation) 3 Q_PROPERTY(QColor barColor READ getBarColor WRITE setBarColor)
- 一個屬性的行為就像類的數據成員,但是它還具有附加的特性,這些特性可以被元數據對象系統操作。這些特性是:
需要一個READ訪問器函數。用於讀屬性的值。理想情況下,有一個不變的函數用於此目的,並且它必須返回屬性的類型的值或指針或引用。例如,QWidget::focus是一個只讀的屬性,它對應一個讀函數:QWidget::hasFocus()。 - 一個可選的WRITE訪問器函數。它用於設置屬性的值。它必須返回空並且至少具有一個參數,參數是屬性類型的值或指針或引用。例如:QWidget::enabled具有WRITE函數QWidget::setEnable()。只讀屬性不需要寫函數。例如,QWidget::focus沒有對應的寫函數。
- 一個可選的RESET函數。用於設置屬性的值到它的默認值。例如:QWidget::cursor具有典型的READ和WRITE函數,QWidget::cursor()和QWidget::setCursor(),並且它也具有一個RESET函數,QWidget::unsetCursor()。RESET函數必須返回void並且不帶有任何參數。
- 一個可選的NOTIFY信號。如果被定義了,信號將在屬性的值改變時發出。信號必須帶有一個參數,這個參數的類型必須與屬性相同;參數保存的是屬性的新值。
- 一個DESIGNABLE變量表明此屬性是否在界面設計器的屬性編輯器中出現。大多數屬性是可見的,除了為這個變量傳入true或false,你還可以指定一個bool型的成員函數。
- SCRIPTABLE變量表明這個屬性是否可以被一個腳本引擎操作(默認是true)。你也可以賦予它true或false或bool型函數。
- STORED變量表明了屬性是否被認為是獨立存在還是依賴於其它的值而存在。它也表明是否在保存對象狀態時保存此屬性的值。大多數屬性都是需要保存的,但是,如QWidget::minimumWidth()就是不被保存的,因為它的值是從另一個屬性QWidget::minimumSize()得來的。
- USER變量表明屬性是否被設計為面向用戶的或用戶可修改的類屬性。通常,每個類只有一個USER屬性。例如,QAbstractButton::checked是按鈕類的用戶可修改屬性。注意QItemDelegate獲取和設置widget的USER屬性。
- CONSTANT的出現表明屬性的值是不變的。對於一個object實例,常量屬性的READ方法在每次被調用時必須返回相同的值。此常量值可能在不同的object實例中不相同。一個常量屬性不能具有WRITE方法或NOYIFY信號。
- FINAL變量的出現表明屬性不能被派生類所重寫。有些情況下,這可以用於效率優化,但不是被moc強制的。程序員必須永遠注意不能重寫一個FINAL屬性。
READ,WRITE和RESET函數都可以被繼承。它們也可以是虛函數。當它們在被多重繼承中被繼承時,它們必須出現在第一個被繼承的類中。
屬性的類型可以是被QVariant支持的所有類型,也可以是用戶定義的類型。在下面的例子中,類QDate被當作用戶自定義類型。
Q_PROPERTY(QDate data READ getDate WRITE setDate)
因為QDate是用戶定義的,你必須包含<QDate>頭文件。
對於QMap,QList和QValueList屬性,屬性的值是一個QVariant,它包含整個list或map。注意Q_PROPERTY字符串不能包含逗號,因為逗號會划分宏的參數。因此,你必須使用QMap作為屬性的類型而不是QMap<QString,QVariant>。為了保持一致性,也需要用QList和QValueList而不是QList<QVariant>和QValueList<QVariant>。
代碼調用的例子:
1 class Test : public QObject { 2
3 Q_OBJECT 4
5 Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) 6
7 public: 8
9 Test(QObject *parent = 0) : QObject(parent) {} 10
11 virtual ~Test(){} 12
13 void setEnabled(bool e) { enabled = e; } 14
15 bool isEnabled() const { return enabled; } 16
17 private: 18
19 bool enabled; 20
21 };
然后在主函數中添加:
1 Test *test = new Test; 2
3 test->setProperty("enabled", true); 4
5 //test->setEnabled(true); //ok also work
6
7 if(test->property("enabled").toBool()) .....
Qt Creator Designer插件的 例子:
頭文件中定義了一個minValue 的屬性,如下:
1 class BarRuler : public QWidget 2 { 3 Q_OBJECT 4 Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue) 5
6 public: 7 explicit BarRuler(QWidget *parent = 0); 8 ~BarRuler(); 9
10 private: 11 double minValue; 12
13 public: 14 double getMinValue() const; 15
16 public slots: 17 void setRange(double minValue, double maxValue); 18 };
cpp文件實現如下:
1 #include "barruler.h"
2
3 BarRuler::BarRuler(QWidget *parent) : QWidget(parent) 4 { 5 minValue = 0; 6 } 7
8 BarRuler::~BarRuler() 9 { 10 } 11
12 double BarRuler::getMinValue() const
13 { 14 return this->minValue; 15 } 16
17 void BarRuler::setMinValue(double minValue) 18 { 19 this->minValue = minValue; 20 update(); 21 }
在設計模式界面調用如下:
1、先拖入一個widget控件
2、在其上右鍵選擇“提升為”BarRuler
3、點擊屬性欄的加號,選擇其它類型,如圖
4、類型和名稱都要和頭文件里定義的相同,如圖
5、在屬性欄就會出現對應的動態屬性,如圖
6、修改數值,就會改變相對應定義的屬性了