Das Eigenschaftssystem
Qt bietet ein ausgeklügeltes Eigenschaftssystem, das dem von einigen Compilerherstellern angebotenen ähnelt. Als compiler- und plattformunabhängige Bibliothek ist Qt jedoch nicht auf nicht standardisierte Compilerfunktionen wie __property
oder [property]
angewiesen. Die Qt-Lösung funktioniert mit jedem Standard-C++-Compiler auf jeder von Qt unterstützten Plattform. Sie basiert auf dem Meta-Objektsystem, das auch die Kommunikation zwischen Objekten über Signale und Slots ermöglicht.
Voraussetzungen für die Deklaration von Eigenschaften
Um eine Eigenschaft zu deklarieren, verwenden Sie das Makro Q_PROPERTY() in einer Klasse, die QObject erbt.
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] [REQUIRED])
Hier sind einige typische Beispiele für Eigenschaftsdeklarationen aus der Klasse 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)
Das folgende Beispiel zeigt, wie man mit dem Schlüsselwort MEMBER
Member-Variablen als Qt-Eigenschaften exportieren kann. Beachten Sie, dass ein NOTIFY
Signal angegeben werden muss, um QML-Eigenschaftsbindungen zu ermöglichen.
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;
Eine Eigenschaft verhält sich wie ein Datenelement der Klasse, hat aber zusätzliche Funktionen, die über das Meta-Objektsystem zugänglich sind.
- Eine
READ
Accessor-Funktion ist erforderlich, wenn keineMEMBER
Variable angegeben wurde. Sie dient zum Lesen des Eigenschaftswertes. Idealerweise wird für diesen Zweck eine const-Funktion verwendet, die entweder den Typ der Eigenschaft oder eine const-Referenz auf diesen Typ zurückgeben muss. QWidget::focus ist z. B. eine schreibgeschützte Eigenschaft mit der FunktionREAD
, QWidget::hasFocus(). Wenn einBINDABLE
angegeben ist, können SieREAD default
schreiben, um denREAD
Accessor aus demBINDABLE
zu generieren. - Eine
WRITE
-Accessor-Funktion ist optional. Sie dient zum Setzen des Eigenschaftswertes. Sie muss void zurückgeben und genau ein Argument annehmen, entweder vom Typ der Eigenschaft oder einen Zeiger oder Verweis auf diesen Typ. z.B. hat QWidget::enabled die FunktionWRITE
QWidget::setEnabled (). Nur-Lese-Eigenschaften benötigen keineWRITE
Funktionen. z.B. QWidget::focus hat keineWRITE
Funktion. Wenn Sie sowohlBINDABLE
als auchWRITE default
angeben, wird einWRITE
Accessor ausBINDABLE
generiert. Der generierteWRITE
Accessor wird kein explizit mitNOTIFY
deklariertes Signal ausgeben. Sie sollten das Signal als Änderungshandler fürBINDABLE
registrieren, z. B. mit Q_OBJECT_BINDABLE_PROPERTY. - Eine
MEMBER
Variablenverknüpfung ist erforderlich, wenn keineREAD
Accessorfunktion angegeben ist. Dadurch wird die angegebene Mitgliedsvariable lesbar und beschreibbar, ohne dassREAD
undWRITE
Accessorfunktionen erstellt werden müssen. Es ist immer noch möglich,READ
oderWRITE
Accessor-Funktionen zusätzlich zurMEMBER
Variablen-Zuordnung zu verwenden (aber nicht beides), wenn Sie den Zugriff auf die Variable kontrollieren müssen. - Eine
RESET
Funktion ist optional. Sie dient dazu, die Eigenschaft auf ihren kontextspezifischen Standardwert zurückzusetzen. QWidget::cursor hat z. B. die typischen FunktionenREAD
undWRITE
, QWidget::cursor() und QWidget::setCursor(), und es gibt auch eine FunktionRESET
, QWidget::unsetCursor(), da kein Aufruf von QWidget::setCursor() das Zurücksetzen auf den kontextspezifischen Cursor bedeuten kann. Die FunktionRESET
muss void zurückgeben und keine Parameter annehmen. - Ein
NOTIFY
Signal ist optional. Wenn es definiert ist, sollte es ein bestehendes Signal in dieser Klasse angeben, das immer dann ausgegeben wird, wenn sich der Wert der Eigenschaft ändert.NOTIFY
Signale fürMEMBER
Variablen müssen null oder einen Parameter annehmen, der vom gleichen Typ wie die Eigenschaft sein muss. Der Parameter nimmt den neuen Wert der Eigenschaft an. Das SignalNOTIFY
sollte nur dann ausgegeben werden, wenn die Eigenschaft tatsächlich geändert wurde, um zu vermeiden, dass Bindungen z.B. in QML unnötig neu ausgewertet werden. Das Signal wird automatisch ausgegeben, wenn die Eigenschaft über die Qt-API (QObject::setProperty, QMetaProperty, etc.) geändert wird, aber nicht, wenn das MEMBER direkt geändert wird. - Eine
REVISION
Nummer oder einREVISION()
Makro ist optional. Wenn es enthalten ist, definiert es die Eigenschaft und das Signal für den Notifier, das in einer bestimmten Revision der API verwendet werden soll (normalerweise für den Kontakt mit QML). Wenn es nicht enthalten ist, ist es standardmäßig auf 0 gesetzt. - Das Attribut
DESIGNABLE
gibt an, ob die Eigenschaft im Eigenschaftseditor des GUI-Design-Tools (z. B. Qt Widgets Designer) sichtbar sein soll. Die meisten Eigenschaften sindDESIGNABLE
(Standardwert true). Gültige Werte sind true und false. - Das Attribut
SCRIPTABLE
gibt an, ob diese Eigenschaft von einer Skripting-Engine zugänglich sein soll (Standardwert true). Gültige Werte sind true und false. - Das Attribut
STORED
gibt an, ob die Eigenschaft als eigenständig oder abhängig von anderen Werten betrachtet werden soll. Es gibt auch an, ob der Eigenschaftswert gespeichert werden muss, wenn der Zustand des Objekts gespeichert wird. Die meisten Eigenschaften sindSTORED
(Standardwert true), aber z. B. QWidget::minimumWidth() hatSTORED
false, weil ihr Wert nur von der Breitenkomponente der Eigenschaft QWidget::minimumSize() übernommen wird, die eine QSize ist. - Das Attribut
USER
gibt an, ob die Eigenschaft als benutzerorientierte oder vom Benutzer editierbare Eigenschaft für die Klasse bestimmt ist. Normalerweise gibt es nur eineUSER
Eigenschaft pro Klasse (Standardwert false). QAbstractButton::checked ist z. B. die vom Benutzer editierbare Eigenschaft für (ankreuzbare) Schaltflächen. Beachten Sie, dass QItemDelegate die EigenschaftUSER
eines Widgets erhält und festlegt. - Das
BINDABLE bindableProperty
Attribut zeigt an, dass die Eigenschaft Bindungen unterstützt und dass es möglich ist, Bindungen zu dieser Eigenschaft über das Meta-Objektsystem zu setzen und zu überprüfen (QMetaProperty).bindableProperty
benennt ein Klassenmitglied vom Typ QBindable<T>, wobei T der Typ der Eigenschaft ist. Dieses Attribut wurde in Qt 6.0 eingeführt. - Das Vorhandensein des Attributs
CONSTANT
zeigt an, dass der Eigenschaftswert konstant ist. Für eine gegebene Objektinstanz muss die READ-Methode einer konstanten Eigenschaft jedes Mal, wenn sie aufgerufen wird, denselben Wert zurückgeben. Dieser konstante Wert kann für verschiedene Instanzen des Objekts unterschiedlich sein. Eine konstante Eigenschaft kann weder eine WRITE-Methode noch ein NOTIFY-Signal haben. - Das Vorhandensein des Attributs
FINAL
zeigt an, dass die Eigenschaft nicht von einer abgeleiteten Klasse überschrieben werden kann. Dies kann in einigen Fällen für Leistungsoptimierungen genutzt werden, wird aber von moc nicht erzwungen. Es muss darauf geachtet werden, dass eineFINAL
Eigenschaft niemals überschrieben wird. - Das Vorhandensein des
REQUIRED
Attributs zeigt an, dass die Eigenschaft von einem Benutzer der Klasse gesetzt werden sollte. Dies wird von moc nicht erzwungen und ist hauptsächlich für Klassen nützlich, die QML ausgesetzt sind. In QML können Klassen mit REQUIRED-Eigenschaften erst dann instanziiert werden, wenn alle REQUIRED-Eigenschaften gesetzt wurden.
Die Funktionen READ
, WRITE
, und RESET
können vererbt werden. Sie können auch virtuell sein. Wenn sie in Klassen vererbt werden, in denen Mehrfachvererbung verwendet wird, müssen sie von der ersten vererbten Klasse stammen.
Der Eigenschaftstyp kann ein beliebiger Typ sein, der von QVariant unterstützt wird, oder er kann ein benutzerdefinierter Typ sein. In diesem Beispiel wird die Klasse QDate als benutzerdefinierter Typ betrachtet.
Q_PROPERTY(QDate date READ getDate WRITE setDate)
Da QDate benutzerdefiniert ist, müssen Sie die Header-Datei <QDate>
in die Eigenschaftsdeklaration aufnehmen.
Aus historischen Gründen sind QMap und QList als Eigenschaftstypen Synonyme für QVariantMap und QVariantList.
Lesen und Schreiben von Eigenschaften mit dem Meta-Objektsystem
Eine Eigenschaft kann mit den generischen Funktionen QObject::property() und QObject::setProperty() gelesen und geschrieben werden, ohne dass man außer dem Namen der Eigenschaft etwas über die besitzende Klasse weiß. Im folgenden Codeschnipsel setzen sowohl der Aufruf von QAbstractButton::setDown() als auch der Aufruf von QObject::setProperty() die Eigenschaft "down".
QPushButton *button = new QPushButton; QObject *object = button; button->setDown(true); object->setProperty("down", true);
Der Zugriff auf eine Eigenschaft über den Accessor WRITE
ist der bessere der beiden Wege, da er schneller ist und bessere Diagnosen zur Kompilierzeit liefert. Durch den Zugriff auf Eigenschaften über den Namen können Sie auf Klassen zugreifen, die Ihnen zur Kompilierzeit nicht bekannt sind. Sie können die Eigenschaften einer Klasse zur Laufzeit ermitteln, indem Sie ihre QObject, QMetaObject und QMetaProperties abfragen.
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); ... }
In dem obigen Ausschnitt wird QMetaObject::property() verwendet, um metadata über jede in einer unbekannten Klasse definierte Eigenschaft abzurufen. Der Eigenschaftsname wird aus den Metadaten geholt und an QObject::property() übergeben, um die value der Eigenschaft in der aktuellen object zu erhalten.
Ein einfaches Beispiel
Angenommen, wir haben eine Klasse MyClass
, die von QObject abgeleitet ist und das Makro Q_OBJECT verwendet. Wir wollen eine Eigenschaft in MyClass
deklarieren, um einen Prioritätswert zu verfolgen. Der Name der Eigenschaft wird priority
sein, und ihr Typ wird ein Aufzählungstyp namens Priority
sein, der in MyClass
definiert ist.
Wir deklarieren die Eigenschaft mit dem Makro Q_PROPERTY() im privaten Abschnitt der Klasse. Die erforderliche Funktion READ
heißt priority
, und wir schließen eine Funktion WRITE
mit dem Namen setPriority
ein. Der Aufzählungstyp muss im Meta-Objektsystem mit dem Makro Q_ENUM() registriert werden. Durch die Registrierung eines Aufzählungstyps werden die Aufzählungsnamen für die Verwendung in Aufrufen von QObject::setProperty() verfügbar. Wir müssen auch unsere eigenen Deklarationen für die Funktionen READ
und WRITE
bereitstellen. Die Deklaration von MyClass
könnte dann wie folgt aussehen:
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; };
Die Funktion READ
ist const und gibt den Eigenschaftstyp zurück. Die Funktion WRITE
gibt void zurück und hat genau einen Parameter des Eigenschaftstyps. Der Meta-Object Compiler setzt diese Anforderungen durch. Die Gleichheitsprüfung in der Funktion WRITE
ist zwar nicht obligatorisch, aber eine gute Praxis, da es keinen Sinn macht, dies zu melden und möglicherweise eine erneute Evaluierung an anderen Stellen zu erzwingen, wenn sich nichts geändert hat.
Mit einem Zeiger auf eine Instanz von MyClass
oder einem Zeiger auf eine QObject, die eine Instanz von MyClass
ist, haben wir zwei Möglichkeiten, die Prioritätseigenschaft zu setzen:
MyClass *myinstance = new MyClass; QObject *object = myinstance; myinstance->setPriority(MyClass::VeryHigh); object->setProperty("priority", "VeryHigh");
Im Beispiel wird der Aufzählungstyp, der der Eigenschaftstyp ist, in MyClass
deklariert und mit dem Makro Q_ENUM() im Meta-Objektsystem registriert. Dadurch stehen die Aufzählungswerte als Zeichenketten zur Verfügung, die wie im Aufruf von setProperty() verwendet werden können. Wäre der Aufzählungstyp in einer anderen Klasse deklariert worden, wäre sein voll qualifizierter Name (d. h. OtherClass::Priority) erforderlich, und diese andere Klasse müsste ebenfalls QObject erben und den Aufzählungstyp dort mit dem Makro Q_ENUM() registrieren.
Ein ähnliches Makro, Q_FLAG(), ist ebenfalls verfügbar. Wie Q_ENUM() registriert es einen Aufzählungstyp, aber es kennzeichnet den Typ als einen Satz von Flags, d. h. von Werten, die miteinander ODER-verknüpft werden können. Eine E/A-Klasse könnte die Aufzählungswerte Read
und Write
haben und QObject::setProperty() könnte dann Read | Write
akzeptieren. Q_FLAG() sollte verwendet werden, um diesen Aufzählungstyp zu registrieren.
Dynamische Eigenschaften
QObject::setProperty() kann auch verwendet werden, um einer Instanz einer Klasse zur Laufzeit neue Eigenschaften hinzuzufügen. Wenn sie mit einem Namen und einem Wert aufgerufen wird, wird der Wert in der Eigenschaft gespeichert und true zurückgegeben, wenn eine Eigenschaft mit dem angegebenen Namen in QObject existiert und der angegebene Wert mit dem Typ der Eigenschaft kompatibel ist. Wenn der Wert nicht mit dem Typ der Eigenschaft kompatibel ist, wird die Eigenschaft nicht geändert und false wird zurückgegeben. Wenn jedoch die Eigenschaft mit dem angegebenen Namen in QObject nicht existiert (d.h. wenn sie nicht mit Q_PROPERTY() deklariert wurde), wird automatisch eine neue Eigenschaft mit dem angegebenen Namen und Wert zu QObject hinzugefügt, aber false wird trotzdem zurückgegeben. Das bedeutet, dass ein Rückgabewert von false nicht verwendet werden kann, um festzustellen, ob eine bestimmte Eigenschaft tatsächlich gesetzt wurde, es sei denn, Sie wissen im Voraus, dass die Eigenschaft bereits in QObject existiert.
Beachten Sie, dass dynamische Eigenschaften pro Instanz hinzugefügt werden, d.h. sie werden zu QObject hinzugefügt, nicht zu QMetaObject. Eine Eigenschaft kann aus einer Instanz entfernt werden, indem der Eigenschaftsname und ein ungültiger QVariant Wert an QObject::setProperty() übergeben wird. Der Standardkonstruktor für QVariant konstruiert eine ungültige QVariant.
Dynamische Eigenschaften können mit QObject::property() abgefragt werden, genau wie Eigenschaften, die zur Kompilierzeit mit Q_PROPERTY() deklariert wurden.
Eigenschaften und benutzerdefinierte Typen
Benutzerdefinierte Typen, die von Eigenschaften verwendet werden, müssen mit dem Makro Q_DECLARE_METATYPE() registriert werden, damit ihre Werte in QVariant Objekten gespeichert werden können. Dadurch eignen sie sich sowohl für statische Eigenschaften, die mit dem Makro Q_PROPERTY() in Klassendefinitionen deklariert werden, als auch für dynamische Eigenschaften, die zur Laufzeit erstellt werden.
Hinzufügen zusätzlicher Informationen zu einer Klasse
Mit dem Eigenschaftssystem verbunden ist ein zusätzliches Makro, Q_CLASSINFO(), mit dem zusätzliche Name-Wert-Paare an das Meta-Objekt einer Klasse angehängt werden können. Dies wird z.B. verwendet, um eine Eigenschaft als Standard-Eigenschaft im Kontext von QML-Objekttypen zu markieren:
Q_CLASSINFO("DefaultProperty", "content")
Wie andere Metadaten sind Klasseninformationen zur Laufzeit über das Meta-Objekt zugänglich; siehe QMetaObject::classInfo() für Details.
Verwendung von bindbaren Eigenschaften
Drei verschiedene Typen können verwendet werden, um bindbare Eigenschaften zu implementieren:
Der erste Typ ist eine allgemeine Klasse für bindbare Eigenschaften. Die beiden letzteren können nur innerhalb einer QObject verwendet werden.
Weitere Informationen, einschließlich Beispiele, finden Sie in den oben genannten Klassen und in den allgemeinen Tipps zur Implementierung und Verwendung von bindbaren Eigenschaften.
Siehe auch Meta-Objektsystem, Signale und Slots, Q_DECLARE_METATYPE(), QMetaType, QVariant, Qt Bindable Properties und Defining QML Types from C++.
© 2025 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.