プロパティシステム
Qt は、一部のコンパイラベンダーが提供しているものと同様の、洗練されたプロパティシステムを備えています。 しかし、コンパイラやプラットフォームに依存しないライブラリである Qt は、__property や[property] といった非標準のコンパイラ機能には依存していません。Qt のソリューションは、Qt がサポートするすべてのプラットフォーム上の、あらゆる標準 C++ コンパイラで動作します。これは、シグナルとスロットを介したオブジェクト間の通信も提供するメタオブジェクトシステムに基づいています。
プロパティを宣言するための要件
プロパティを宣言するには、QObject を継承するクラス内でQ_PROPERTY()マクロを使用します。
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int | REVISION(int[, int])]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[BINDABLE bindableProperty]
[CONSTANT]
[FINAL]
[VIRTUAL]
[OVERRIDE]
[REQUIRED])以下は、クラス `QWidget` から抜粋した、プロパティ宣言の典型的な例です。
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)以下は、MEMBER キーワードを使用してメンバー変数をQtプロパティとしてエクスポートする方法を示す例です。QMLでのプロパティバインディングを可能にするには、NOTIFY シグナルを指定する必要があることに注意してください。
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged)
Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
//...
signals:
void colorChanged();
void spacingChanged();
void textChanged(const QString &newText);
private:
QColor m_color;
qreal m_spacing;
QString m_text;プロパティはクラスのデータメンバーと同様に動作しますが、メタオブジェクトシステムを通じてアクセス可能な追加機能を備えています。
MEMBER変数が指定されていない場合は、READアクセサ関数が必須となります。これは、プロパティの値を読み取るためのものです。 理想的には、この目的には const 関数が使用され、その関数はプロパティの型、またはその型への const 参照のいずれかを返さなければなりません。例:QWidget::focus は、READ関数QWidget::hasFocus()を持つ読み取り専用プロパティです。BINDABLEが指定されている場合、READ defaultと記述することで、BINDABLEからREADアクセサが生成されます。WRITEアクセサ関数はオプションです。これはプロパティの値を設定するためのものです。この関数はvoidを返す必要があり、引数を正確に1つ受け取る必要があります。引数はプロパティの型、またはその型へのポインタもしくは参照のいずれかです。例:QWidget::enabled には、WRITE関数QWidget::setEnabled()があります。 読み取り専用プロパティには、WRITE関数は必要ありません。例えば、QWidget::focus にはWRITE関数がありません。BINDABLEとWRITE defaultの両方を指定した場合、BINDABLEからWRITEアクセサが生成されます。生成されたWRITEアクセサは、NOTIFYで宣言されたシグナルを明示的に発信しません。シグナルをBINDABLEの変更ハンドラとして登録する必要があります。例えば、Q_OBJECT_BINDABLE_PROPERTY を使用します。READアクセサ関数が指定されていない場合、MEMBER変数アソシエーションが必要です。これにより、READおよびWRITEアクセサ関数を作成することなく、指定されたメンバ変数を読み書きできるようになります。変数へのアクセスを制御する必要がある場合は、MEMBER変数アソシエーションに加えて、READまたはWRITEアクセサ関数を使用することも可能です(ただし、両方を同時に使用することはできません)。RESET関数はオプションです。これは、プロパティをコンテキスト固有のデフォルト値に戻すためのものです。例えば、QWidget::cursor には、一般的なREADおよびWRITE関数であるQWidget::cursor()とQWidget::setCursor()に加え、RESET関数であるQWidget::unsetCursor()も存在します。これは、QWidget::setCursor()が呼び出されない場合、コンテキスト固有のカーソルにリセットされることを意味するためです。RESET関数はvoidを返し、引数を取ってはなりません。NOTIFYシグナルはオプションです。定義される場合、プロパティの値が変更されるたびに発火される、そのクラス内の既存のシグナルを1つ指定する必要があります。MEMBER変数に対するNOTIFYシグナルは、パラメータを0個または1個受け取る必要があり、その型はプロパティと同じでなければなりません。パラメータには、プロパティの新しい値が渡されます。NOTIFYシグナルは、例えばQt Qml内でバインディングが不必要に再評価されるのを防ぐため、プロパティが実際に変更された場合にのみ発火させるべきです。このシグナルは、Qt API(QObject::setProperty 、QMetaProperty など)を介してプロパティが変更された場合には自動的に発火しますが、MEMBERが直接変更された場合には発火しません。REVISIONの数値またはREVISION()マクロはオプションです。これを含める場合、そのプロパティおよびその通知シグナルがAPIの特定のバージョンで使用されることを定義します(通常はQMLへの公開用)。含まれない場合、デフォルトは0となります。DESIGNABLE属性は、そのプロパティをGUI設計ツールのプロパティエディタ(例: Qt Widgets Designer)のGUIデザインツールのプロパティエディタに表示されるかどうかを示します。ほとんどのプロパティはDESIGNABLEです(デフォルトはtrue)。有効な値はtrueとfalseです。SCRIPTABLE属性は、このプロパティがスクリプトエンジンからアクセス可能であるべきかどうかを示します(デフォルトはtrue)。有効な値はtrueとfalseです。STORED属性は、そのプロパティが独立して存在するものとして扱われるべきか、それとも他の値に依存するものとして扱われるべきかを指定します。また、オブジェクトの状態を保存する際に、そのプロパティの値を保存する必要があるかどうかも指定します。 ほとんどのプロパティは「STORED」(デフォルトは true)ですが、例えばQWidget::minimumWidth() のSTOREDは false です。これは、その値がQWidget::minimumSize() プロパティの width コンポーネントから取得されるだけであり、 () は「QSize 」であるためです。USER属性は、そのプロパティがクラスにおいてユーザー向けプロパティとして指定されているか、あるいはユーザー編集可能プロパティとして指定されているかを示します。通常、クラスごとにUSERプロパティは1つだけ存在します(デフォルトはfalse)。例えば、QAbstractButton::checked は(チェック可能な)ボタンのユーザー編集可能プロパティです。なお、QItemDelegate はウィジェットのUSERプロパティを取得および設定することに注意してください。BINDABLE bindableProperty属性は、そのプロパティがバインディングをサポートしており、メタオブジェクトシステム(QMetaProperty )を介してこのプロパティへのバインディングを設定および検査できることを示します。bindablePropertyは、QBindable<T>型のクラスメンバーを指定します。ここで、Tはプロパティの型です。この属性はQt 6.0で導入されました。CONSTANT属性が存在する場合、そのプロパティの値は定数であることを示します。特定のオブジェクトインスタンスに対して、定数プロパティのREADメソッドは、呼び出されるたびに同じ値を返さなければなりません。この定数値は、オブジェクトのインスタンスごとに異なる場合があります。定数プロパティには、WRITEメソッドやNOTIFYシグナルを定義することはできません。FINALVIRTUAL、 修飾子は、OVERRIDEC++およびQMLの対応する修飾子の意味論を反映しており、メタオブジェクトレベルでプロパティのオーバーライドを明示的に行うことを可能にします。注:現時点では 、これらの修飾子は moc によって強制されません。これらは構文的に認識され、主に QML Runtime での強制やツールによる診断に使用されます。将来のバージョンでは、モジュール間の無効なオーバーライドに対して、より厳格なコンパイル時の検証や警告が導入される可能性があります。
注: プロパティへのアクセス挙動を変更したい場合は 、C++ が提供する多態性を使用してください。
REQUIRED属性が存在する場合、そのプロパティはクラスのユーザーによって設定される必要があることを示します。これはmocによって強制されるものではなく、主にQMLに公開されるクラスで有用です。QMLでは、REQUIREDプロパティを持つクラスは、すべてのREQUIREDプロパティが設定されない限りインスタンス化できません。
READ 、WRITE 、およびRESET 関数は継承可能です。また、これらを仮想関数とすることもできます。多重継承が使用されているクラスでこれらを継承する場合、最初の継承元クラスから継承する必要があります。
プロパティの型は、QVariant でサポートされている任意の型、またはユーザー定義型にすることができます。この例では、クラスQDate はユーザー定義型とみなされます。
Q_PROPERTY(QDate date READ getDate WRITE setDate)QDate はユーザー定義であるため、プロパティの宣言には<QDate> ヘッダーファイルを含める必要があります。
歴史的な理由により、プロパティ型としての `QMap ` および `QList ` は、`QVariantMap ` および `QVariantList` と同義です。
メタオブジェクトシステムを用いたプロパティの読み書き
プロパティは、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 、およびQMetaProperties をクエリすることで検出できます。
QObject *object = new QObject;
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 を取得しています。プロパティ名はメタデータから取得され、QObject::property() に渡されて、現在のobject におけるそのプロパティのvalue が取得されます。
簡単な例
QObject から派生し、Q_OBJECT マクロを使用するクラスMyClass があるとします。MyClass にプロパティを宣言して、優先度値を管理したいとします。プロパティ名はpriority とし、その型はMyClass で定義されているPriority という列挙型とします。
このプロパティは、クラスのプライベートセクションでQ_PROPERTY() マクロを使用して宣言します。必須のREAD 関数はpriority と名付けられ、WRITE 関数としてsetPriority を定義します。列挙型は、Q_ENUM()マクロを使用してメタオブジェクトシステムに登録する必要があります。列挙型を登録することで、QObject::setProperty() の呼び出しにおいて列挙子の名前を使用できるようになります。 また、READ およびWRITE 関数についても、独自の宣言を用意する必要があります。MyClass の宣言は、次のような形になるでしょう:
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
MyClass(QObject *parent = nullptr);
~MyClass();
enum Priority { High, Low, VeryHigh, VeryLow };
Q_ENUM(Priority)
void setPriority(Priority priority)
{
if (m_priority == priority)
return;
m_priority = priority;
emit priorityChanged(priority);
}
Priority priority() const
{ return m_priority; }
signals:
void priorityChanged(Priority);
private:
Priority m_priority;
};READ 関数はconstであり、プロパティ型を返します。WRITE 関数はvoidを返し、プロパティ型のパラメータをちょうど1つ持ちます。Meta-Object Compilerはこれらの要件を強制します。WRITE 関数における等価性チェックは必須ではありませんが、変更がない場合に他の場所で通知を行い、再評価を強制する可能性があるのは意味がないため、良い慣行と言えます。
MyClass のインスタンスへのポインタ、またはMyClass のインスタンスであるQObject へのポインタが与えられた場合、そのpriorityプロパティを設定するには2つの方法があります:
MyClass *myinstance = new MyClass;
QObject *object = myinstance;
myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority", "VeryHigh");この例では、プロパティの型である列挙型が `MyClass ` 内で宣言され、`Q_ENUM()` マクロを使用してメタオブジェクトシステムに登録されています。これにより、列挙値は文字列として利用可能となり、`setProperty()` の呼び出しで利用できるようになります。 もし列挙型が別のクラスで宣言されていた場合、その完全修飾名(つまり、OtherClass::Priority)が必要となり、その別のクラスもQObject を継承し、Q_ENUM()マクロを使用してそこで列挙型を登録する必要があります。
同様のマクロとして、Q_FLAG()も利用可能です。Q_ENUM()と同様に、列挙型を登録しますが、このマクロは型をフラグの集合、すなわち論理和(OR)で結合可能な値の集合としてマークします。 あるI/Oクラスに、Read やWrite といった列挙値があり、QObject::setProperty()がRead | Write を受け入れる場合、この列挙型を登録するにはQ_FLAG()を使用する必要があります。
動的プロパティ
QObject::setProperty() を使用すると、実行時にクラスのインスタンスに新しいプロパティを追加することもできます。 名前と値を引数として呼び出された場合、指定された名前を持つプロパティが `QObject` に存在し、かつ指定された値がそのプロパティの型と互換性があるならば、その値はプロパティに格納され、`true` が返されます。値がそのプロパティの型と互換性がない場合、プロパティは変更されず、`false` が返されます。 しかし、指定された名前のプロパティがQObject に存在しない場合(つまり、Q_PROPERTY()で宣言されていない場合)、指定された名前と値を持つ新しいプロパティが自動的にQObject に追加されますが、それでもfalseが返されます。 つまり、そのプロパティがQObject にすでに存在することを事前に知っていない限り、falseが返されたことをもって、特定のプロパティが実際に設定されたかどうかを判断することはできません。
動的プロパティはインスタンスごとに追加されることに注意してください。つまり、それらはQMetaObject ではなく、QObject に追加されます。プロパティ名と無効なQVariant 値をQObject::setProperty() に渡すことで、インスタンスからプロパティを削除できます。QVariant のデフォルトコンストラクタは、無効なQVariant を生成します。
動的プロパティは、コンパイル時にQ_PROPERTY()で宣言されたプロパティと同様に、QObject::property()を使用してクエリできます。
プロパティとカスタム型
プロパティで使用されるカスタム型は、その値がQVariant オブジェクトに格納されるように、Q_DECLARE_METATYPE()マクロを使用して登録する必要があります。これにより、クラス定義でQ_PROPERTY()マクロを使用して宣言された静的プロパティと、実行時に作成される動的プロパティの両方で使用できるようになります。
クラスへの追加情報の付加
プロパティシステムに関連して、Q_CLASSINFO() という追加のマクロがあり、これを使用することで、クラスのメタオブジェクトに追加の名前と値のペアを関連付けることができます。これは、例えば、QML Object Types のコンテキストにおいて、あるプロパティをデフォルトのプロパティとしてマークするために使用されます:
Q_CLASSINFO("DefaultProperty", "content")他のメタデータと同様に、クラス情報も実行時にメタオブジェクトを通じてアクセス可能です。詳細については、QMetaObject::classInfo() を参照してください。
バインド可能なプロパティの使用
バインド可能なプロパティを実装するには、以下の3つの型を使用できます:
1つ目は、バインド可能なプロパティのための汎用クラスです。後者の2つは、QObject 内でのみ使用可能です。
例を含む詳細については、前述のクラスおよびバインド可能なプロパティの実装と使用に関する一般的なヒントを参照してください。
「メタオブジェクトシステム」、「シグナルとスロット」、「Q_DECLARE_METATYPE()」、「QMetaType 」、「QVariant 」、「Qt バインダブルプロパティ」、および「C++ からの QML 型の定義」も参照してください 。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.