Qt-Bindable-Eigenschaften
Qt bietet bindbare Eigenschaften. Bindbare Eigenschaften sind Eigenschaften, die entweder einen Wert haben oder mithilfe einer beliebigen C++-Funktion, typischerweise eines C++-Lambda-Ausdrucks, festgelegt werden. Werden sie mithilfe einer C++-Funktion festgelegt, werden sie automatisch aktualisiert, sobald sich ihre Abhängigkeiten ändern.
Bindbare Eigenschaften werden in der Klasse „ QProperty “ implementiert, die aus dem Datenobjekt und einem Zeiger auf eine Verwaltungsdatenstruktur besteht, sowie in der Klasse „ QObjectBindableProperty “, die nur aus dem Datenobjekt besteht und die kapselnde Klasse „ QObject “ verwendet, um den Zeiger auf die Verwaltungsdatenstruktur zu speichern.
Warum bindbare Eigenschaften verwenden?
Eigenschaftsbindungen sind eine der Kernfunktionen von QML. Sie ermöglichen es, Beziehungen zwischen verschiedenen Objekteigenschaften festzulegen und die Werte der Eigenschaften automatisch zu aktualisieren, sobald sich ihre Abhängigkeiten ändern. Mit bindbaren Eigenschaften lässt sich dies nicht nur im QML-Code, sondern auch in C++ erreichen. Die Verwendung bindbarer Eigenschaften kann dazu beitragen, Ihr Programm zu vereinfachen, indem viel Standardcode für die Verfolgung und Reaktion auf Abhängigkeitsaktualisierungen verschiedener Objekte entfällt.
Das folgende Einführungsbeispiel veranschaulicht die Verwendung von bindbaren Eigenschaften in C++-Code. Sie können sich auch das Beispiel zu bindbaren Eigenschaften ansehen, um zu erfahren, wie diese dazu beitragen können, Ihren Code zu verbessern.
Einführungsbeispiel
Der Bindungsausdruck berechnet den Wert, indem er Werte aus anderen „ QProperty “ ausliest. Im Hintergrund wird diese Abhängigkeit nachverfolgt. Sobald eine Änderung in der Abhängigkeit einer Eigenschaft erkannt wird, wird der Bindungsausdruck neu ausgewertet und das neue Ergebnis auf die Eigenschaft angewendet. Zum Beispiel:
QProperty<QString> firstname("John");
QProperty<QString> Nachname("Smith");
QProperty<int> Alter(41);
QProperty<QString> Vollname;
Vollname.setBinding([&]() { return Vorname.value() + " " + Nachname.value() + " Alter: " + QString::number(age.value()); });
qDebug() << fullname.value(); // Prints "John Smith age: 41"
firstname = "Emma"; // Löst eine Neubewertung der Bindungen aus
qDebug() << fullname.value(); // Prints the new value "Emma Smith age: 41"
// Der Geburtstag steht bevor
age.setValue(age.value() + 1); // Löst eine Neubewertung aus
qDebug() << fullname.value(); // Prints "Emma Smith age: 42"Wenn der Eigenschaft „ firstname “ ein neuer Wert zugewiesen wird, wird der Bindungsausdruck für „ fullname “ neu ausgewertet. Wenn also die letzte Anweisung „ qDebug() “ versucht, den Namenwert der Eigenschaft „ fullname “ auszulesen, wird der neue Wert zurückgegeben.
Da Bindungen C++-Funktionen sind, können sie alles tun, was in C++ möglich ist. Dazu gehört auch der Aufruf anderer Funktionen. Wenn diese Funktionen auf Werte zugreifen, die von QProperty gehalten werden, werden sie automatisch zu Abhängigkeiten der Bindung.
Bindungsausdrücke können Eigenschaften beliebigen Typs verwenden; im obigen Beispiel ist das Alter also eine Ganzzahl und wird durch die Konvertierung in eine Ganzzahl in den Zeichenfolgenwert eingebunden, doch die Abhängigkeit wird vollständig nachverfolgt.
Bindbare Eigenschafts-Getter und -Setter
Wenn eine Klasse über eine bindbare Eigenschaft verfügt – sei es mithilfe von ` QProperty ` oder ` QObjectBindableProperty` –, ist bei der Definition der Getter und Setter für diese Eigenschaft besondere Sorgfalt geboten.
Getter für bindbare Eigenschaften
Um den ordnungsgemäßen Betrieb des automatischen Abhängigkeitsverfolgungssystems zu gewährleisten, muss jeder mögliche Codepfad in einem Getter aus dem zugrunde liegenden Eigenschaftsobjekt gelesen werden. Außerdem darf die Eigenschaft innerhalb des Getters nicht geschrieben werden. Entwurfsmuster, die im Getter etwas neu berechnen oder aktualisieren, sind mit bindbaren Eigenschaften nicht kompatibel.
Es wird daher empfohlen, bei bindbaren Eigenschaften nur einfache Getter zu verwenden.
Setter für bindbare Eigenschaften
Um den ordnungsgemäßen Betrieb des automatischen Abhängigkeitsverfolgungssystems zu gewährleisten, muss jeder mögliche Codepfad in einem Setter in das zugrunde liegende Eigenschaftsobjekt schreiben, selbst wenn sich der Wert nicht geändert hat.
Jeder andere Code in einem Setter weist mit hoher Wahrscheinlichkeit Fehler auf. Code, der Aktualisierungen auf Basis des neuen Werts vornimmt, ist höchstwahrscheinlich ein Fehler, da dieser Code nicht ausgeführt wird, wenn die Eigenschaft über eine Bindung geändert wird.
Es wird daher empfohlen, bei bindbaren Eigenschaften nur einfache Setter zu verwenden.
Schreiben in eine bindbare Eigenschaft
Bindbare Eigenschaften informieren ihre abhängigen Eigenschaften über jede Änderung. Dies kann Änderungshandler auslösen, die wiederum beliebigen Code aufrufen können. Daher muss jeder Schreibvorgang in eine bindbare Eigenschaft sorgfältig geprüft werden. Die folgenden Probleme können auftreten.
Schreiben von Zwischenwerten in bindbare Eigenschaften
Bindbare Eigenschaften dürfen nicht als Variablen in Algorithmen verwendet werden. Jeder geschriebene Wert würde an abhängige Eigenschaften weitergeleitet werden. Im folgenden Code würden beispielsweise andere Eigenschaften, die von `myProperty` abhängen, zunächst über die Änderung auf 42 und anschließend über die Änderung auf `maxValue` informiert werden.
myProperty = somecomputation(); // returning, say, 42
if (myProperty.value() > maxValue)
myProperty = maxValue;Führen Sie die Berechnung stattdessen in einer separaten Variablen durch. Die korrekte Verwendung wird im folgenden Beispiel gezeigt.
int newValue = someComputation();
if (newValue > maxValue)
newValue = maxValue;
myProperty = newValue; // only write to the property onceSchreiben in bindbare Eigenschaften in Übergangszuständen
Wenn eine bindbare Eigenschaft ein Mitglied einer Klasse ist, könnte jeder Schreibvorgang auf diese Eigenschaft den aktuellen Zustand nach außen offenlegen. Daher dürfen bindbare Eigenschaften nicht in Übergangszuständen geschrieben werden, in denen Klasseninvarianten nicht erfüllt sind.
Beispielsweise könnte in einer Klasse, die einen Kreis darstellt und die beiden Elemente „radius“ und „area“ konsistent hält, ein Setter wie folgt aussehen (wobei „radius“ eine bindbare Eigenschaft ist):
void setRadius(double newValue)
{
radius = newValue; // this might trigger change handlers
area = M_PI * radius * radius;
emit radiusChanged();
}Hier könnte Code, der in Änderungshandlern ausgelöst wird, den Kreis verwenden, während dieser zwar den neuen Radius, aber noch die alte Fläche hat.
Bindbare Eigenschaften mit virtuellen Settern und Gettern
Eigenschafts-Setter und -Getter sollten normalerweise minimal sein und nichts anderes tun, als die Eigenschaft zu setzen; daher ist es in der Regel nicht sinnvoll, solche Setter und Getter virtuell zu definieren. Es gibt nichts, was die abgeleitete Klasse sinnvollerweise tun könnte.
Einige Qt-Klassen können jedoch Eigenschaften mit virtuellen Settern haben. Beim Erstellen einer Unterklasse einer solchen Qt-Klasse ist beim Überschreiben solcher Setter besondere Vorsicht geboten.
In jedem Fall muss die Basisimplementierung aufgerufen werden, damit die Bindung korrekt funktioniert.
Das Folgende veranschaulicht diesen Ansatz.
void DerivedClass::setValue(int val)
{
// do something
BaseClass::setValue(val);
// probably do something else
}Alle allgemeinen Regeln und Empfehlungen zum Schreiben in bindbare Eigenschaften gelten auch hier. Sobald die Basisklassenimplementierung aufgerufen wird, werden alle Beobachter über die Änderung der Eigenschaft benachrichtigt. Das bedeutet, dass Klasseninvarianten erfüllt sein müssen, bevor die Basisklassenimplementierung aufgerufen wird.
In dem seltenen Fall, in dem solche virtuellen Getter oder Setter erforderlich sind, sollte die Basisklasse die Anforderungen dokumentieren, die sie an Überschreibungen stellt.
Formulierung einer Eigenschaftsbindung
Jeder C++-Ausdruck, der den korrekten Typ ergibt, kann als Bindungsausdruck verwendet und an die Methode `setBinding()` übergeben werden. Um jedoch eine korrekte Bindung zu formulieren, müssen einige Regeln beachtet werden.
Die Abhängigkeitsverfolgung funktioniert nur bei bindbaren Eigenschaften. Es liegt in der Verantwortung des Entwicklers, sicherzustellen, dass alle im Bindungsausdruck verwendeten Eigenschaften bindbare Eigenschaften sind. Werden nicht-bindbare Eigenschaften in einem Bindungsausdruck verwendet, lösen Änderungen an diesen Eigenschaften keine Aktualisierungen der gebundenen Eigenschaft aus. Weder zur Kompilierungszeit noch zur Laufzeit wird eine Warnung oder ein Fehler ausgegeben. Die gebundene Eigenschaft wird nur aktualisiert, wenn sich die im Bindungsausdruck verwendeten bindbaren Eigenschaften ändern. Nicht bindbare Eigenschaften dürfen in einer Bindung verwendet werden, wenn sichergestellt werden kann, dass bei jeder Änderung der nicht bindbaren Abhängigkeit die Methode `markDirty` für die zu bindende Eigenschaft aufgerufen wird.
Die gebundene Eigenschaft kann ihre Bindung während ihrer Lebensdauer mehrmals auswerten. Der Entwickler muss sicherstellen, dass alle im Bindungsausdruck verwendeten Objekte länger bestehen als die Bindung.
Das System der bindbaren Eigenschaften ist nicht threadsicher. Eigenschaften, die in einem Bindungsausdruck in einem Thread verwendet werden, dürfen von keinem anderen Thread gelesen oder geändert werden. Ein Objekt einer von ` QObject` abgeleiteten Klasse, das eine Eigenschaft mit einer Bindung besitzt, darf nicht in einen anderen Thread verschoben werden. Ebenso darf ein Objekt einer von ` QObject` abgeleiteten Klasse, das eine in einer Bindung verwendete Eigenschaft besitzt, nicht in einen anderen Thread verschoben werden. In diesem Zusammenhang ist es unerheblich, ob es in einer Bindung einer Eigenschaft desselben Objekts oder in einer Bindung einer Eigenschaft eines anderen Objekts verwendet wird.
Der Bindungsausdruck darf nicht aus der Eigenschaft lesen, für die er eine Bindung darstellt. Andernfalls entsteht eine Auswerteschleife.
Der Bindungsausdruck darf nicht in die Eigenschaft schreiben, für die er eine Bindung darstellt.
Funktionen, die als Bindungen verwendet werden, sowie jeglicher Code, der innerhalb einer Bindung aufgerufen wird, dürfen kein `co_await` verwenden. Dies kann die Verfolgung von Abhängigkeiten durch das Eigenschaftssystem beeinträchtigen.
Bindbare Eigenschaften und Multithreading
Bindbare Eigenschaften sind nicht threadsicher, sofern nicht anders angegeben. Eine bindbare Eigenschaft darf von keinem anderen Thread als demjenigen, in dem sie erstellt wurde, gelesen oder geändert werden.
Verfolgung bindbarer Eigenschaften
Manchmal lassen sich die Beziehungen zwischen Eigenschaften nicht mithilfe von Bindungen ausdrücken. Stattdessen müssen Sie möglicherweise benutzerdefinierten Code ausführen, sobald sich der Wert einer Eigenschaft ändert, und diesen Wert, anstatt ihn einer anderen Eigenschaft zuzuweisen, an andere Teile Ihrer Anwendung weitergeben. Beispiele hierfür sind das Schreiben von Daten in einen Netzwerk-Socket oder das Ausgeben von Debug-Informationen. „ QProperty “ bietet zwei Mechanismen zur Nachverfolgung.
Mit `onValueChanged()` können Sie eine Callback-Funktion registrieren, die immer dann aufgerufen wird, wenn sich der Wert einer Eigenschaft ändert. Wenn der Callback auch für den aktuellen Wert der Eigenschaft aufgerufen werden soll, registrieren Sie Ihren Callback stattdessen mit `subscribe()`.
Interaktion mit Q_PROPERTY
Eine Q_PROPERTY, die „ BINDABLE “ definiert, kann gebunden und in Bindungsausdrücken verwendet werden. Sie können solche Eigenschaften mithilfe von „ QProperty “, „ QObjectBindableProperty “ oder „ QObjectComputedProperty “ implementieren.
Auch Q_PROPERTYs ohne ` BINDABLE ` können gebunden und in Bindungsausdrücken verwendet werden, sofern sie ein ` NOTIFY `-Signal definieren. Sie müssen die Eigenschaft mithilfe des Konstruktors „ QBindable(QObject* obj, const char* property) “ in eine „ QBindable “ einbinden. Anschließend kann die Eigenschaft mit „ QBindable::setBinding()“ gebunden oder über „ QBindable::value()“ in einem Bindungsausdruck verwendet werden. Sie müssen in Bindungsausdrücken „ QBindable::value() “ anstelle der normalen Eigenschaftsfunktion „ READ “ (oder „ MEMBER “) verwenden, um die Abhängigkeitsverfolgung zu aktivieren, sofern die Eigenschaft nicht „ BINDABLE “ ist.
© 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.