Auf dieser Seite

Das Eigenschaftssystem

Qt bietet ein ausgeklügeltes Eigenschaftssystem, das den von einigen Compiler-Anbietern bereitgestellten Systemen ähnelt. Als kompilierer- und plattformunabhängige Bibliothek ist Qt jedoch nicht auf nicht standardisierte Compiler-Funktionen 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 Metaobjektsystem, 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 von ` 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]
           [VIRTUAL]
           [OVERRIDE]
           [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)

Hier ist ein Beispiel, das zeigt, wie Membervariablen mithilfe des Schlüsselworts „ MEMBER “ als Qt-Eigenschaften exportiert werden. Beachten Sie, dass ein Signal von „ NOTIFY “ 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 Klassen-Datenelement, verfügt jedoch über zusätzliche Funktionen, auf die über das Metaobjektsystem zugegriffen werden kann.

  • Eine „ READ “-Zugriffsfunktion ist erforderlich, wenn keine „ MEMBER “-Variable angegeben wurde. Sie dient zum Auslesen des Eigenschaftswerts. Idealerweise wird hierfür eine `const`-Funktion verwendet, die entweder den Typ der Eigenschaft oder eine `const`-Referenz auf diesen Typ zurückgeben muss. Beispiel: ` QWidget::focus ` ist eine schreibgeschützte Eigenschaft mit der Funktion ` READ `, ` QWidget::hasFocus()`. Wenn ein ` BINDABLE ` angegeben ist, können Sie ` READ default ` schreiben, damit der Accessor ` READ ` aus dem ` BINDABLE` generiert wird.
  • Eine WRITE -Zugriffsfunktion ist optional. Sie dient zum Setzen des Eigenschaftswerts. Sie muss `void` zurückgeben und genau ein Argument entgegennehmen, das entweder vom Typ der Eigenschaft ist oder ein Zeiger bzw. eine Referenz auf diesen Typ darstellt. Beispielsweise verfügt QWidget::enabled über die WRITE -Funktion QWidget::setEnabled(). Schreibgeschützte Eigenschaften benötigen keine „ WRITE “-Funktionen. Beispielsweise verfügt „ QWidget::focus “ über keine „ WRITE “-Funktion. Wenn Sie sowohl eine „ BINDABLE “- als auch eine „ WRITE default “-Funktion angeben, wird aus der „ BINDABLE “-Funktion ein „ WRITE “-Zugriffsfunktion generiert. Die generierte „ WRITE “-Zugriffsfunktion gibt keine Signale aus, die mit „ NOTIFY “ deklariert wurden. Sie sollten das Signal als Änderungshandler bei der „ BINDABLE “ registrieren, beispielsweise mithilfe von „ Q_OBJECT_BINDABLE_PROPERTY “.
  • Eine Variablenzuordnung vom Typ „ MEMBER “ ist erforderlich, wenn keine Zugriffsfunktion vom Typ „ READ “ angegeben ist. Dadurch wird die angegebene Member-Variable les- und schreibbar, ohne dass Zugriffsfunktionen vom Typ „ READ “ und „ WRITE “ erstellt werden müssen. Es ist weiterhin möglich, zusätzlich zur Variablenzuordnung vom Typ „ MEMBER “ die Zugriffsfunktionen „ READ “ oder „ WRITE “ zu verwenden (jedoch nicht beide), falls Sie den Zugriff auf die Variable steuern müssen.
  • Eine „ RESET “-Funktion ist optional. Sie dient dazu, die Eigenschaft wieder auf ihren kontextspezifischen Standardwert zurückzusetzen. Beispielsweise verfügt „ QWidget::cursor “ über die typischen „ READ “- und „ WRITE “-Funktionen „ QWidget::cursor()“ und „ QWidget::setCursor()“ sowie über eine „ RESET “-Funktion „ QWidget::unsetCursor()“, da das Fehlen eines Aufrufs von „ QWidget::setCursor()“ ein Zurücksetzen auf den kontextspezifischen Cursor bedeuten kann. Die „ RESET “-Funktion muss den Rückgabetyp „void“ haben und darf keine Parameter annehmen.
  • Ein Signal „ NOTIFY “ ist optional. Falls definiert, sollte es ein vorhandenes Signal in dieser Klasse angeben, das immer dann ausgelöst wird, wenn sich der Wert der Eigenschaft ändert. „ NOTIFY “-Signale für „ MEMBER “-Variablen müssen null oder einen Parameter annehmen, der denselben Typ wie die Eigenschaft haben muss. Der Parameter erhält den neuen Wert der Eigenschaft. Das Signal „ NOTIFY “ sollte nur dann ausgelöst werden, wenn die Eigenschaft tatsächlich geändert wurde, um beispielsweise zu vermeiden, dass Bindungen in QML unnötigerweise neu ausgewertet werden. Das Signal wird automatisch ausgelöst, wenn die Eigenschaft über die Qt-API (QObject::setProperty, QMetaProperty usw.) geändert wird, jedoch nicht, wenn das MEMBER direkt geändert wird.
  • Eine „ REVISION “-Zahl oder ein „ REVISION() “-Makro ist optional. Wenn es angegeben wird, definiert es die Eigenschaft und ihr Notifier-Signal für die Verwendung in einer bestimmten Version der API (in der Regel zur Bereitstellung für QML). Ist es nicht angegeben, wird standardmäßig der Wert 0 verwendet.
  • Das Attribut „ DESIGNABLE “ gibt an, ob die Eigenschaft im Eigenschaftseditor eines GUI-Designtools (z. B. „Qt Widgets Designer“) sichtbar sein soll. Die meisten Eigenschaften sind standardmäßig sichtbar ( DESIGNABLE, Standardwert „true“). Gültige Werte sind „true“ und „false“.
  • Das Attribut „ SCRIPTABLE “ gibt an, ob diese Eigenschaft für eine Skript-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 als von anderen Werten abhängig betrachtet werden soll. Es gibt außerdem an, ob der Eigenschaftswert beim Speichern des Objektzustands gespeichert werden muss. Die meisten Eigenschaften sind „ STORED “ (Standard: „true“), aber z. B. „ QWidget::minimumWidth()“ hat „ STORED “ auf „false“ gesetzt, da sein Wert lediglich aus der Breitenkomponente der Eigenschaft „ QWidget::minimumSize()“ übernommen wird, die eine „ QSize “ ist.
  • Das Attribut „ USER “ gibt an, ob die Eigenschaft als benutzersichtbare oder benutzerbearbeitbare Eigenschaft für die Klasse festgelegt ist. Normalerweise gibt es nur eine „ USER “-Eigenschaft pro Klasse (Standardwert „false“). Beispielsweise ist „ QAbstractButton::checked “ die benutzerbearbeitbare Eigenschaft für (aktivierbare) Schaltflächen. Beachten Sie, dass „ QItemDelegate “ die Eigenschaft „ USER “ eines Widgets abruft und setzt.
  • Das Attribut „ BINDABLE bindableProperty “ gibt an, dass die Eigenschaft Bindungen unterstützt und dass es möglich ist, Bindungen an diese Eigenschaft über das Metaobjektsystem (`QMetaProperty`) festzulegen und zu überprüfen. „ bindableProperty “ benennt ein Klassenmitglied vom Typ ` QBindable<T>`, wobei `T` der Eigenschaftstyp 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 bestimmte Objektinstanz muss die READ-Methode einer konstanten Eigenschaft bei jedem Aufruf denselben Wert zurückgeben. Dieser konstante Wert kann für verschiedene Instanzen des Objekts unterschiedlich sein. Eine konstante Eigenschaft darf keine WRITE-Methode und kein NOTIFY-Signal haben.
  • FINALDie Modifizierer „ VIRTUAL “ und „ OVERRIDE “ spiegeln die Semantik ihrer C++- und QML-Entsprechungen wider und ermöglichen es, das Überschreiben von Eigenschaften auf der Metaobjekt-Ebene explizit zu machen.

    Hinweis: Derzeit werden diese Modifikatoren von moc nicht erzwungen. Sie werden syntaktisch erkannt und dienen in erster Linie der Durchsetzung bei QML Runtime sowie der Diagnose durch Entwicklungstools. Zukünftige Versionen könnten strengere Validierungen zur Kompilierungszeit sowie Warnungen bei ungültigen Überschreibungen über Module hinweg einführen.

    Hinweis: Wenn Sie das Zugriffsverhalten einer Eigenschaft ändern möchten, nutzen Sie den von C++ bereitgestellten Polymorphismus.

  • Das Vorhandensein des Attributs „ REQUIRED “ gibt an, dass die Eigenschaft von einem Benutzer der Klasse gesetzt werden sollte. Dies wird von moc nicht erzwungen und ist vor allem für Klassen nützlich, die für QML freigegeben sind. In QML können Klassen mit „REQUIRED“-Eigenschaften erst 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 aus der ersten vererbten Klasse stammen.

Der Eigenschaftstyp kann ein beliebiger von ` QVariant` unterstützter Typ oder 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> “ bei der Eigenschaftsdeklaration einbinden.

Aus historischen Gründen sind „ QMap “ und „ QList “ als Eigenschaftstypen Synonyme für „ QVariantMap “ und „ QVariantList “.

Lesen und Schreiben von Eigenschaften mit dem Metaobjektsystem

Eine Eigenschaft kann mithilfe der generischen Funktionen ` QObject::property()` und ` QObject::setProperty()` gelesen und geschrieben werden, ohne dass man etwas über die zugehörige Klasse weiß, außer dem Namen der Eigenschaft. Im folgenden Codeausschnitt 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 ihren WRITE -Zugriffsoperator ist die bessere der beiden Möglichkeiten, da er schneller ist und eine bessere Diagnose zur Kompilierungszeit ermöglicht; allerdings setzt das Setzen der Eigenschaft auf diese Weise voraus, dass Sie die Klasse bereits zur Kompilierungszeit kennen. Der Zugriff auf Eigenschaften über ihren Namen ermöglicht es Ihnen, auf Klassen zuzugreifen, die Ihnen zur Kompilierungszeit noch nicht bekannt sind. Sie können die Eigenschaften einer Klasse zur Laufzeit ermitteln, indem Sie deren QObject, QMetaObject und QMetaProperties abfragen.

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);
    //...
}

Im obigen Codeausschnitt wird ` QMetaObject::property()` verwendet, um ` metadata ` für jede in einer unbekannten Klasse definierte Eigenschaft abzurufen. Der Eigenschaftsname wird aus den Metadaten abgerufen und an ` QObject::property()` übergeben, um die ` value ` der Eigenschaft im 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 möchten eine Eigenschaft in ` MyClass ` deklarieren, um einen Prioritätswert zu verfolgen. Der Name der Eigenschaft lautet ` priority`, und ihr Typ ist ein Aufzählungstyp namens ` Priority`, der in ` MyClass` definiert ist.

Wir deklarieren die Eigenschaft mit dem Makro „ Q_PROPERTY()“ im privaten Bereich der Klasse. Die erforderliche Funktion „ READ “ heißt „ priority “, und wir fügen eine Funktion „ WRITE “ mit dem Namen „ setPriority “ ein. Der Aufzählungstyp muss mithilfe des Makros „ Q_ENUM()“ im Meta-Objekt-System registriert werden. Durch die Registrierung eines Aufzählungstyps stehen die Namen der Aufzählungselemente für Aufrufe von „ QObject::setProperty()“ zur Verfügung. Außerdem müssen wir eigene 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 von Typ `const` und gibt den Eigenschaftstyp zurück. Die Funktion ` WRITE ` gibt `void` zurück und hat genau einen Parameter vom Eigenschaftstyp. Der Meta-Object Compiler sorgt für die Einhaltung dieser Anforderungen. Die Gleichheitsprüfung in der Funktion ` WRITE ` ist zwar nicht zwingend erforderlich, gilt jedoch als bewährte Vorgehensweise, da es keinen Sinn macht, an anderen Stellen eine Benachrichtigung auszulösen und möglicherweise eine Neubewertung zu erzwingen, wenn sich nichts geändert hat.

Bei einem Zeiger auf eine Instanz von ` MyClass ` oder einem Zeiger auf ein ` QObject `, das eine Instanz von ` MyClass` ist, gibt es zwei Möglichkeiten, die Prioritätseigenschaft festzulegen:

MyClass *myinstance = new MyClass;
QObject *object = myinstance;

myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority", "VeryHigh");

Im Beispiel ist der Aufzählungstyp, der den Eigenschaftstyp darstellt, in ` MyClass ` deklariert und mithilfe des Makros ` Q_ENUM()` im Metaobjektsystem 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 dessen vollqualifizierter Name (d. h. `OtherClass::Priority`) erforderlich, und diese andere Klasse müsste ebenfalls von ` QObject ` erben und den Aufzählungstyp dort mithilfe des Makros ` Q_ENUM()` registrieren.

Ein ähnliches Makro, „ Q_FLAG()“, ist ebenfalls verfügbar. Wie „ Q_ENUM()“ registriert es einen Aufzählungstyp, kennzeichnet den Typ jedoch als eine Menge von Flags, d. h. als Werte, die miteinander verknüpft werden können. Eine I/O-Klasse könnte die Aufzählungswerte „ Read “ und „ Write “ haben, und dann könnte „ QObject::setProperty()“ „ Read | Write “ akzeptieren. Zur Registrierung dieses Aufzählungstyps sollte „ Q_FLAG()“ verwendet werden.

Dynamische Eigenschaften

QObject::setProperty() kann auch verwendet werden, um einer Instanz einer Klasse zur Laufzeit neue Eigenschaften hinzuzufügen. Wird die Methode mit einem Namen und einem Wert aufgerufen, wird der Wert in der Eigenschaft gespeichert und „true“ zurückgegeben, sofern eine Eigenschaft mit dem angegebenen Namen im „ QObject “ vorhanden ist und der angegebene Wert mit dem Typ der Eigenschaft kompatibel ist. Ist der Wert nicht mit dem Typ der Eigenschaft kompatibel, wird die Eigenschaft nicht geändert und „false“ zurückgegeben. Existiert die Eigenschaft mit dem angegebenen Namen jedoch nicht im „ QObject “ (d. h., wenn sie nicht mit „ Q_PROPERTY()“ deklariert wurde), wird dem „ QObject “ automatisch eine neue Eigenschaft mit dem angegebenen Namen und Wert hinzugefügt, es wird jedoch weiterhin „false“ zurückgegeben. Das bedeutet, dass die Rückgabe von „false“ nicht dazu verwendet werden kann, festzustellen, ob eine bestimmte Eigenschaft tatsächlich gesetzt wurde, es sei denn, Sie wissen im Voraus, dass die Eigenschaft bereits im „ QObject “ vorhanden ist.

Beachten Sie, dass dynamische Eigenschaften instanzspezifisch hinzugefügt werden, d. h., sie werden dem ` QObject` hinzugefügt, nicht dem ` QMetaObject`. Eine Eigenschaft kann aus einer Instanz entfernt werden, indem der Eigenschaftsname und ein ungültiger ` QVariant `-Wert an ` QObject::setProperty()` übergeben werden. Der Standardkonstruktor für ` QVariant ` erstellt ein ungültiges ` QVariant`.

Dynamische Eigenschaften können mit ` QObject::property()` abgefragt werden, genau wie Eigenschaften, die zur Kompilierungszeit mit ` Q_PROPERTY()` deklariert wurden.

Eigenschaften und benutzerdefinierte Typen

Benutzerdefinierte Typen, die von Eigenschaften verwendet werden, müssen mithilfe des Makros „ Q_DECLARE_METATYPE()“ registriert werden, damit ihre Werte in „ QVariant “-Objekten gespeichert werden können. Dadurch eignen sie sich sowohl für die Verwendung mit statischen Eigenschaften, die mithilfe des Makros „ Q_PROPERTY()“ in Klassendefinitionen deklariert wurden, als auch für dynamische Eigenschaften, die zur Laufzeit erstellt wurden.

Hinzufügen zusätzlicher Informationen zu einer Klasse

Mit dem Eigenschaftssystem verbunden ist ein zusätzliches Makro, ` Q_CLASSINFO()`, mit dem zusätzlicheName-Wert-Paare an das Metaobjekt einer Klasse angehängt werden können. Dies wird beispielsweise verwendet, um eine Eigenschaft im Kontext von ` QML Object Types` als Standard-Eigenschaft zu kennzeichnen:

Q_CLASSINFO("DefaultProperty", "content")

Wie andere Metadaten sind auch Klasseninformationen zur Laufzeit über das Metaobjekt zugänglich; siehe „ QMetaObject::classInfo()“ für weitere Details.

Verwendung bindbarer Eigenschaften

Zur Implementierung bindbarer Eigenschaften können drei verschiedene Typen verwendet werden:

Der erste ist eine allgemeine Klasse für bindbare Eigenschaften. Die beiden anderen können nur innerhalb eines ` QObject` verwendet werden.

Weitere Informationen, einschließlich Beispielen, finden Sie in den oben genannten Klassen sowie in den allgemeinen Hinweisen zur Implementierung und Verwendung bindbarer Eigenschaften.

Siehe auch Metaobjektsystem, Signale und Slots, ` Q_DECLARE_METATYPE()`, ` QMetaType`, ` QVariant`, Qt-bindbare Eigenschaften und Definieren von QML-Typen aus C++.

© 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.