1. 程式人生 > >Qt之自定義屬性Q_PROPERTY

Qt之自定義屬性Q_PROPERTY

 

相當於定義了某一個數據屬性,此資料可讀性,可寫性、復位值、訊號關聯等內容

    Qt提供了一個絕妙的屬性系統。跟那些由編譯器提供的屬性差不多。然而,作為一個獨立於編譯器和平臺的庫,Qt不依賴於非標準的編譯特性,比如__property 或[property]。Qt可以在任何平臺上的標準編譯器下編譯。Qt屬性系統基於元資料物件系統--就是那個提供了物件內建訊號和槽通訊機制的傢伙。

    Q_PROPERTY()是一個巨集,用來在一個類中宣告一個屬性property,由於該巨集是qt特有的,需要用moc進行編譯,故必須繼承於QObject類。

Q_PROPERTY(type name
   READ getFunction
   [WRITE setFunction]
   [RESET resetFunction]
   [NOTIFY notifySignal]
   [DESIGNABLE bool]
   [SCRIPTABLE bool]
   [STORED bool]
   [USER bool]
   [CONSTANT]
   [FINAL])

下面是一些典型的宣告屬性的示例:

Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue)
Q_PROPERTY(bool animation READ getAnimation WRITE setAnimation)
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>。
 

程式碼呼叫的例子:

 

class Test : public QObject {  
  
Q_OBJECT  
  
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)  
  
public:  
  
Test(QObject *parent = 0) : QObject(parent) {}  
  
virtual ~Test(){}  
  
void setEnabled(bool e) { enabled = e; }  
  
bool isEnabled() const { return enabled; }  
  
private:  
  
bool enabled;  
  
};  

然後在主函式中新增:

 

Test *test = new Test;  
  
test->setProperty("enabled", true);  
  
//test->setEnabled(true);        //ok also work  
  
if(test->property("enabled").toBool()) ..... 


Qt Creator Designer外掛的例子:

標頭檔案中定義了一個minValue 的屬性,如下:

 

class BarRuler : public QWidget
{
    Q_OBJECT    
    Q_PROPERTY(double minValue READ getMinValue WRITE setMinValue)

public:
    explicit BarRuler(QWidget *parent = 0);
    ~BarRuler();

private:    
    double minValue;

public:    
    double getMinValue()            const;

public slots:
    void setRange(double minValue, double maxValue);
};


cpp檔案實現如下:

 

#include "barruler.h"

BarRuler::BarRuler(QWidget *parent) : QWidget(parent)
{    
    minValue = 0;
}

BarRuler::~BarRuler()
{
}

double BarRuler::getMinValue() const
{
    return this->minValue;
}

void BarRuler::setMinValue(double minValue)
{
    this->minValue = minValue;
    update();
}


在設計模式介面呼叫如下:

1、先拖入一個widget控制元件

2、在其上右鍵選擇“提升為”BarRuler

3、點選屬性欄的加號,選擇其它型別,如圖

4、型別和名稱都要和標頭檔案裡定義的相同,如圖

5、在屬性欄就會出現對應的動態屬性,如圖

6、修改數值,就會改變相對應定義的屬性了