[セットトップ]Qtプロパティシステムの詳細
6616 ワード
Qtは絶妙な属性システムを提供した.コンパイラによって提供されるプロパティとはあまり差がありません.しかしながら、コンパイラおよびプラットフォームから独立したライブラリとして、Qtは、__などの非標準的なコンパイル特性に依存しない.propertyまたは[property].Qtは、任意のプラットフォーム上の標準コンパイラの下でコンパイルできます.Qt属性システムはメタデータオブジェクトシステムに基づいている--オブジェクト内蔵信号とスロット通信メカニズムを提供するやつである.
属性を宣言するには、QObjectから継承されたクラスでQ_を使用します.PROPERTY()マクロ.
Q_PROPERTY(type name
READ getFunction
[WRITE setFunction]
[RESET resetFunction]
[NOTIFY notifySignal]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
次に、一般的な宣言プロパティの例を示します.プロパティの動作は、クラスのデータ・メンバーのようなものですが、メタデータ・オブジェクト・システムによって動作できる追加のプロパティもあります.これらの特性は、READアクセサ関数が必要です.プロパティの読み取りに使用する値.理想的には、この目的のために不変の関数があり、属性のタイプの値またはポインタまたは参照を返さなければなりません.たとえば、QWidget::focusは読み取り専用のプロパティで、読み取り関数:QWidget::hasFocus()に対応します. オプションのWRITEアクセサ関数.プロパティの値を設定します.空を返し、少なくとも1つのパラメータを持つ必要があります.パラメータは属性タイプの値またはポインタまたは参照です.たとえば、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プロパティが1つしかありません.たとえば、QABstractButton::checkedはボタンクラスのユーザーが属性を変更できます.注意QItemDelegateはwidgetのUSERプロパティを取得して設定します. CONSTANTの出現は属性の値が不変であることを示す.オブジェクトインスタンスの場合、定数属性のREADメソッドは、呼び出されるたびに同じ値を返さなければなりません.この定数値は、異なるobjectインスタンスで異なる場合があります.1つの定数属性はWRITE法またはNOYIFY信号を持つことができない. FINAL変数の出現は、派生クラスによって属性が書き換えられないことを示す.場合によっては効率最適化に使用できるがmocに強制されるわけではない.プログラマは、FINALプロパティを書き換えることができないことに常に注意しなければなりません.
READ,WRITE,RESET関数の両方を継承することができる.虚関数であってもよい.多重継承で継承される場合は、最初に継承されたクラスに表示される必要があります.属性のタイプは、QVariantによってサポートされているすべてのタイプであってもよいし、ユーザ定義のタイプであってもよい.次の例では、クラスQdateはユーザカスタムタイプとして扱われる.Q_PROPERTY(Qate data READ getDate WRITE setDate)Qateはユーザー定義なので、ヘッダファイルを含める必要があります.QMap、QListおよびQValueList属性の場合、属性の値はリストまたはmap全体を含むQVariantです.注意Q_PROPERTY文字列にはカンマを含めることはできません.カンマはマクロのパラメータを分割するからです.したがって、QMapではなく、属性のタイプとしてQMapを使用する必要があります.整合性を保つためには、QListおよびQValueListではなくQListおよびQValueListを用いることも必要である.
1つのプロパティは、通常の関数QObject::property()とQObject::setProperty()を使用して読み書きできます.プロパティの名前を除いて、プロパティが存在するクラスの詳細はわかりません.次の小さなコード・クリップでは、QABstractButton::setDown()とQObject::setProperty()を呼び出し、プロパティを「down」に設定します.
WRITEオペレータでプロパティを操作するのは、コンパイル時により良い診断支援を与えるため、上記の2つのうちより良いですが、このようにプロパティを設定するには、コンパイル時にクラスを理解する必要があります.名前でプロパティを操作すると、コンパイラで知らないクラスを操作できます.実行時にクラスのプロパティを見つけて、QObject、QMetaObject、QMetaProertiesをクエリーできます.
上記のコードクリップでは、QMetaObject::property()を使用して、未知のクラスの属性のmetadataを取得します.metadataから属性名を取得しQObject::property()に渡して取得
QObjectから派生しprivate領域でQ_を使用したクラスMyClassがあるとします.OBJECTマクロ.MyClassクラスに属性を宣言してPriorty値を追跡し続けたいと考えています.属性の値はpriorityと呼ばれ、そのタイプはクラスMyClassで定義されたPriorityという列挙です.クラスのprivate領域でQ_を使用します.PROPERTY()で属性を宣言します.READ関数はpriorityと呼ばれ、setPriorityというWRITE関数が含まれています.列挙タイプはQ_を使用する必要がありますENUMS()はメタデータオブジェクトシステムに登録されている.列挙タイプを登録して、列挙の名前をQObject::setProperty()を呼び出すときに使用できるようにします.READとWRITE関数にも独自の宣言を提供する必要があります.MyClassの声明は次のように見えます.
READ関数はconstであり、属性を返すタイプである.WRITE関数はvoidを返し、属性タイプのパラメータを持つ.メタデータ・オブジェクト・コンパイラは、これらのことを強制します.MyClassインスタンスへのポインタがある場合、priorityプロパティを設定するには2つの方法があります.
この例では、列挙タイプはMyClassで宣言され、Q_が使用される.ENUMS()はメタデータオブジェクトシステムに登録されている.これにより、列挙値はsetProperty()を呼び出すときに文字列として使用できます.列挙タイプが他のクラスで宣言されている場合は、列挙のフルネーム(OtherClass::Priorityなど)が必要であり、この他のクラスもQObjectから派生し、列挙タイプも登録する必要があります.もう一つの簡単なQ_FLAGS()も利用可能です.Q_のようにENUMS()は、列挙タイプを登録しますが、列挙タイプをflagの集合として使用します.つまり、値はOR操作でマージできます.1つのI/Oクラスは、列挙値ReadおよびWriteを有し、QObject::setProperty()はRead|Writeを受け入れることができる.このときQ_を使うFLAGS()は、列挙値を登録する.
Qobject::setProperty()は、実行時にクラスのインスタンスに新しいプロパティを追加するためにも使用できます.名前と値を使用して呼び出すと、対応する属性がすでに存在し、値のタイプが属性のタイプと互換性がある場合、値は属性に格納され、trueに戻ります.値タイプが互換性がない場合、属性の値は変更されずfalseが返されます.しかし、対応する名前の属性が存在しない場合、新しい属性が誕生し、入力された名前を名乗って、入力された値を値にしますが、falseは戻ります.これは、属性がQObjectに存在することを知っていない限り、属性が設定されているかどうかを決定するために戻り値が使用できないことを意味します.なお、ダイナミックプロパティは、単一のインプリメンテーションのベース、すなわち、QMetaObjectではなくQObjectに追加される.1つの属性は、1つのインスタンスから削除され、入力された属性の名前と不正なQVariant値によってQObject::setProperty()に与えられます.デフォルトのQVariantコンストラクタは不正なQVariantを構築します.ダイナミックプロパティはQObject::property()でクエリーできます.Q_を使用します.PROPERTY()宣言のプロパティは同じです.
属性によって使用されるカスタムタイプはQ_を使用する必要がありますDECLARE_METATYPE()マクロは、その値がQVariantオブジェクトに保存されるように登録されている.これにより、Q_PROPERTY()宣言の静的タイプでは、動的タイプでも使用できます.
属性の宣言に必要なもの
属性を宣言するには、QObjectから継承されたクラスでQ_を使用します.PROPERTY()マクロ.
Q_PROPERTY(type name
READ getFunction
[WRITE setFunction]
[RESET resetFunction]
[NOTIFY notifySignal]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
次に、一般的な宣言プロパティの例を示します.
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
READ,WRITE,RESET関数の両方を継承することができる.虚関数であってもよい.多重継承で継承される場合は、最初に継承されたクラスに表示される必要があります.属性のタイプは、QVariantによってサポートされているすべてのタイプであってもよいし、ユーザ定義のタイプであってもよい.次の例では、クラスQdateはユーザカスタムタイプとして扱われる.Q_PROPERTY(Qate data READ getDate WRITE setDate)Qateはユーザー定義なので、
メタデータ・オブジェクト・システムによる属性の読み書き
1つのプロパティは、通常の関数QObject::property()とQObject::setProperty()を使用して読み書きできます.プロパティの名前を除いて、プロパティが存在するクラスの詳細はわかりません.次の小さなコード・クリップでは、QABstractButton::setDown()とQObject::setProperty()を呼び出し、プロパティを「down」に設定します.
QPushButton *button = new QPushButton;
QObject *object = button;
button->setDown(true);
object->setProperty("down", true);
WRITEオペレータでプロパティを操作するのは、コンパイル時により良い診断支援を与えるため、上記の2つのうちより良いですが、このようにプロパティを設定するには、コンパイル時にクラスを理解する必要があります.名前でプロパティを操作すると、コンパイラで知らないクラスを操作できます.実行時にクラスのプロパティを見つけて、QObject、QMetaObject、QMetaProertiesをクエリーできます.
QObject *object = ...
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i=0; i<count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
QVariant value = object->property(name);
...
}
上記のコードクリップでは、QMetaObject::property()を使用して、未知のクラスの属性のmetadataを取得します.metadataから属性名を取得しQObject::property()に渡して取得
簡単な例です
QObjectから派生しprivate領域でQ_を使用したクラスMyClassがあるとします.OBJECTマクロ.MyClassクラスに属性を宣言してPriorty値を追跡し続けたいと考えています.属性の値はpriorityと呼ばれ、そのタイプはクラスMyClassで定義されたPriorityという列挙です.クラスのprivate領域でQ_を使用します.PROPERTY()で属性を宣言します.READ関数はpriorityと呼ばれ、setPriorityというWRITE関数が含まれています.列挙タイプはQ_を使用する必要がありますENUMS()はメタデータオブジェクトシステムに登録されている.列挙タイプを登録して、列挙の名前をQObject::setProperty()を呼び出すときに使用できるようにします.READとWRITE関数にも独自の宣言を提供する必要があります.MyClassの声明は次のように見えます.
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Priority priority READ priority WRITE setPriority)
Q_ENUMS(Priority)
public:
MyClass(QObject *parent = 0);
~MyClass();
enum Priority { High, Low, VeryHigh, VeryLow };
void setPriority(Priority priority);
Priority priority() const;
};
READ関数はconstであり、属性を返すタイプである.WRITE関数はvoidを返し、属性タイプのパラメータを持つ.メタデータ・オブジェクト・コンパイラは、これらのことを強制します.MyClassインスタンスへのポインタがある場合、priorityプロパティを設定するには2つの方法があります.
MyClass *myinstance = new MyClass;
QObject *object = myinstance;
myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority", "VeryHigh");
この例では、列挙タイプはMyClassで宣言され、Q_が使用される.ENUMS()はメタデータオブジェクトシステムに登録されている.これにより、列挙値はsetProperty()を呼び出すときに文字列として使用できます.列挙タイプが他のクラスで宣言されている場合は、列挙のフルネーム(OtherClass::Priorityなど)が必要であり、この他のクラスもQObjectから派生し、列挙タイプも登録する必要があります.もう一つの簡単なQ_FLAGS()も利用可能です.Q_のようにENUMS()は、列挙タイプを登録しますが、列挙タイプをflagの集合として使用します.つまり、値はOR操作でマージできます.1つのI/Oクラスは、列挙値ReadおよびWriteを有し、QObject::setProperty()はRead|Writeを受け入れることができる.このときQ_を使うFLAGS()は、列挙値を登録する.
ダイナミックプロパティ
Qobject::setProperty()は、実行時にクラスのインスタンスに新しいプロパティを追加するためにも使用できます.名前と値を使用して呼び出すと、対応する属性がすでに存在し、値のタイプが属性のタイプと互換性がある場合、値は属性に格納され、trueに戻ります.値タイプが互換性がない場合、属性の値は変更されずfalseが返されます.しかし、対応する名前の属性が存在しない場合、新しい属性が誕生し、入力された名前を名乗って、入力された値を値にしますが、falseは戻ります.これは、属性がQObjectに存在することを知っていない限り、属性が設定されているかどうかを決定するために戻り値が使用できないことを意味します.なお、ダイナミックプロパティは、単一のインプリメンテーションのベース、すなわち、QMetaObjectではなくQObjectに追加される.1つの属性は、1つのインスタンスから削除され、入力された属性の名前と不正なQVariant値によってQObject::setProperty()に与えられます.デフォルトのQVariantコンストラクタは不正なQVariantを構築します.ダイナミックプロパティはQObject::property()でクエリーできます.Q_を使用します.PROPERTY()宣言のプロパティは同じです.
プロパティとカスタムタイプ
属性によって使用されるカスタムタイプはQ_を使用する必要がありますDECLARE_METATYPE()マクロは、その値がQVariantオブジェクトに保存されるように登録されている.これにより、Q_PROPERTY()宣言の静的タイプでは、動的タイプでも使用できます.