Propriétés liées de Qt
Qt fournit des propriétés liables. Les propriétés liables sont des propriétés qui ont une valeur ou qui sont spécifiées à l'aide d'une fonction C++, généralement une expression lambda C++. Si elles sont spécifiées à l'aide d'une fonction C++, elles sont mises à jour automatiquement lorsque leurs dépendances changent.
Les propriétés liables sont implémentées dans la classe QProperty, qui se compose de l'objet de données et d'un pointeur vers une structure de données de gestion, et dans la classe QObjectBindableProperty, qui se compose uniquement de l'objet de données et utilise l'encapsulation QObject pour stocker le pointeur vers la structure de données de gestion.
Pourquoi utiliser des propriétés liables ?
Les liaisons de propriétés sont l'une des principales caractéristiques de QML. Elles permettent de spécifier les relations entre les différentes propriétés d'un objet et de mettre automatiquement à jour les valeurs des propriétés lorsque leurs dépendances changent. Les propriétés liables permettent de réaliser la même chose non seulement dans le code QML, mais aussi en C++. L'utilisation des propriétés liables peut contribuer à simplifier votre programme, en éliminant une grande partie du code standard pour suivre et réagir aux mises à jour des dépendances de différents objets.
L'exemple d'introduction ci-dessous démontre l'utilisation des propriétés liables dans le code C++. Vous pouvez également consulter l'exemple Bindable Properties pour voir comment les propriétés liantes peuvent vous aider à améliorer votre code.
Exemple d'introduction
L'expression de liaison calcule la valeur en lisant d'autres valeurs QProperty. Dans les coulisses, cette dépendance est suivie. Chaque fois qu'un changement dans la dépendance d'une propriété est détecté, l'expression de liaison est réévaluée et le nouveau résultat est appliqué à la propriété. Par exemple, l'expression de liaison est réévaluée et le nouveau résultat est appliqué à la propriété :
QProperty<QString> firstname("John") ;QProperty<QString> nom de famille("Dupont") ;QProperty<int> âge(41) ;QProperty<QString> fullname ; fullname.setBinding([&]() { return firstname.value() + " " + lastname.value() + " age : " + QString::number(age.value()) ; }) ; qDebug() << fullname.value(); // Prints "John Smith age: 41" prénom = "Emma"; // Déclenche la réévaluation de la liaison qDebug() << fullname.value(); // Prints the new value "Emma Smith age: 41" // L'anniversaire approche age.setValue(age.value() + 1) ; // Déclenche une réévaluation qDebug() << fullname.value(); // Prints "Emma Smith age: 42"
Lorsqu'une nouvelle valeur est attribuée à la propriété firstname, l'expression de liaison pour fullname est réévaluée. Ainsi, lorsque la dernière instruction qDebug() tente de lire la valeur du nom de la propriété fullname, la nouvelle valeur est renvoyée.
Étant donné que les liaisons sont des fonctions C++, elles peuvent faire tout ce qui est possible en C++. Cela inclut l'appel à d'autres fonctions. Si ces fonctions accèdent à des valeurs détenues par QProperty, elles deviennent automatiquement des dépendances de la liaison.
Les expressions de liaison peuvent utiliser des propriétés de n'importe quel type ; ainsi, dans l'exemple ci-dessus, l'âge est un nombre entier et est intégré à la valeur de la chaîne de caractères par conversion en nombre entier, mais la dépendance est entièrement prise en compte.
Getters et setters de propriétés liables
Lorsqu'une classe possède une propriété liante, que ce soit à l'aide de QProperty ou de QObjectBindableProperty, il convient de faire preuve d'une attention particulière lors de la formulation des preneurs et des modificateurs de cette propriété.
Getters de propriété liante
Pour garantir le bon fonctionnement du système de suivi automatique des dépendances, chaque chemin de code possible dans un getter doit lire l'objet de propriété sous-jacent. En outre, la propriété ne doit pas être écrite à l'intérieur du getter. Les modèles de conception qui recalculent ou rafraîchissent tout ce qui se trouve dans le getter ne sont pas compatibles avec les propriétés liantes.
Il est par conséquent recommandé de n'utiliser que des getter triviaux avec des propriétés liantes.
Définisseurs de propriétés liantes
Pour garantir le bon fonctionnement du système de suivi automatique des dépendances, chaque chemin de code possible dans un setter doit écrire dans l'objet de propriété sous-jacent, même si la valeur n'a pas changé.
Tout autre code dans un "setter" a de fortes chances d'être incorrect. Tout code effectuant des mises à jour basées sur la nouvelle valeur est très probablement un bogue, car ce code ne sera pas exécuté lorsque la propriété est modifiée par une liaison.
Il est donc recommandé de n'utiliser que des setters triviaux avec les propriétés liables.
Écrire dans une propriété liante
Les propriétés liables informent leurs propriétés dépendantes de chaque changement. Cela peut déclencher des gestionnaires de changement qui, à leur tour, peuvent appeler un code arbitraire. Par conséquent, chaque écriture dans une propriété liante doit être examinée avec soin. Les problèmes suivants peuvent survenir.
Écriture de valeurs intermédiaires dans les propriétés liables
Les propriétés liables ne doivent pas être utilisées comme variables dans les algorithmes. Chaque valeur écrite serait communiquée aux propriétés dépendantes. Par exemple, dans le code suivant, les autres propriétés qui dépendent de myProperty seraient d'abord informées de la modification de 42, puis de la modification de maxValue.
myProperty = somecomputation(); // returning, say, 42
if (myProperty.value() > maxValue)
myProperty = maxValue;Au lieu de cela, effectuez le calcul dans une variable distincte. L'exemple suivant illustre l'utilisation correcte de cette méthode.
int newValue = someComputation(); if (newValue > maxValue) newValue = maxValue; myProperty = newValue; // only write to the property once
Écriture des propriétés liables dans les états transitoires
Lorsqu'une propriété liante est un membre d'une classe, chaque écriture sur cette propriété peut exposer l'état actuel à l'extérieur. Les propriétés liables ne doivent donc pas être écrites dans des états transitoires, lorsque les invariants de la classe ne sont pas respectés.
Par exemple, dans une classe représentant un cercle dont les deux membres radius et area sont cohérents, un setter pourrait ressembler à ceci (où radius est une propriété liante) :
void setRadius(double newValue)
{
radius = newValue; // this might trigger change handlers
area = M_PI * radius * radius;
emit radiusChanged();
}Ici, le code déclenché dans les gestionnaires de changement peut utiliser le cercle, alors qu'il a le nouveau rayon, mais toujours l'ancienne surface.
Propriétés liables avec des setters et des getters virtuels
Les setters et getters de propriétés doivent normalement être minimaux et ne faire rien d'autre que de définir la propriété ; il n'est donc pas approprié que ces setters et getters soient virtuels. Il n'y a rien de logique à ce que la classe dérivée fasse.
Cependant, certaines classes Qt peuvent avoir des propriétés avec des fixateurs virtuels. Lors de la sous-classification d'une telle classe Qt, la surcharge de ces fixateurs nécessite une attention particulière.
Dans tous les cas, l'implémentation de base doit être appelée pour que la liaison fonctionne correctement.
L'exemple suivant illustre cette approche.
void DerivedClass::setValue(int val) { // do something BaseClass::setValue(val); // probably do something else }
Toutes les règles et recommandations communes concernant l'écriture sur des propriétés liables s'appliquent également ici. Dès que l'implémentation de la classe de base est appelée, tous les observateurs sont informés de la modification de la propriété. Cela signifie que les invariants de classe doivent être satisfaits avant d'appeler l'implémentation de base.
Dans les rares cas où de tels getters ou setters virtuels sont nécessaires, la classe de base doit documenter les exigences qu'elle impose aux surcharges.
Formulation d'une liaison de propriété
Toute expression C++ évaluant le bon type peut être utilisée comme expression de liaison et être donnée à la méthode setBinding(). Cependant, pour formuler une liaison correcte, certaines règles doivent être respectées.
Le suivi des dépendances ne fonctionne que sur les propriétés liables. Il incombe au développeur de s'assurer que toutes les propriétés utilisées dans l'expression de liaison sont des propriétés liables. Lorsque des propriétés non liables sont utilisées dans une expression de liaison, les modifications apportées à ces propriétés ne déclenchent pas de mises à jour de la propriété liée. Aucun avertissement ou erreur n'est généré, que ce soit au moment de la compilation ou de l'exécution. La propriété liée ne sera mise à jour que lorsque les propriétés liables utilisées dans l'expression de liaison sont modifiées. Des propriétés non liables peuvent être utilisées dans une liaison s'il est possible de s'assurer que markDirty est appelé sur la propriété liée à chaque changement de la dépendance non liante.
La propriété liée peut évaluer sa liaison plusieurs fois au cours de sa durée de vie. Le développeur doit s'assurer que tous les objets utilisés dans l'expression de liaison vivent plus longtemps que la liaison.
Le système de propriétés liées n'est pas sûr pour les threads. Les propriétés utilisées dans l'expression de liaison sur un thread ne doivent pas être lues ou modifiées par un autre thread. Un objet d'une classe dérivée de QObject qui possède une propriété avec une liaison ne doit pas être déplacé vers un autre thread. De même, un objet d'une classe dérivée de QObject dont une propriété est utilisée dans une liaison ne doit pas être déplacé vers un autre thread. Dans ce contexte, il importe peu qu'elle soit utilisée dans une liaison d'une propriété du même objet ou dans une liaison d'une propriété d'un autre objet.
L'expression de liaison ne doit pas être lue à partir de la propriété pour laquelle elle est liée. Sinon, il y a une boucle d'évaluation.
L'expression de liaison ne doit pas écrire dans la propriété pour laquelle elle est liée.
Les fonctions utilisées comme liaisons ainsi que tout le code appelé à l'intérieur d'une liaison ne doivent pas co_await. Cela peut perturber le suivi des dépendances par le système de propriétés.
Propriétés liantes et multithreading
Les propriétés liables ne sont pas sûres pour les threads, sauf indication contraire. Une propriété liante ne doit pas être lue ou modifiée par un autre thread que celui dans lequel elle a été créée.
Suivi des propriétés liables
Parfois, les relations entre les propriétés ne peuvent pas être exprimées à l'aide de liaisons. Au lieu de cela, vous pouvez avoir besoin d'exécuter un code personnalisé chaque fois que la valeur d'une propriété change et, au lieu d'assigner la valeur à une autre propriété, de la transmettre à d'autres parties de votre application. Par exemple, l'écriture de données dans un socket réseau ou l'impression d'une sortie de débogage. QProperty propose deux mécanismes de suivi.
Vous pouvez enregistrer une fonction de rappel qui sera appelée chaque fois que la valeur d'une propriété change, en utilisant onValueChanged(). Si vous souhaitez que la fonction de rappel soit également appelée pour la valeur actuelle de la propriété, enregistrez votre fonction de rappel en utilisant plutôt subscribe().
Interaction avec Q_PROPERTY
Une propriété Q_PROPERTY qui définit BINDABLE peut être liée et utilisée dans des expressions de liaison. Vous pouvez implémenter de telles propriétés en utilisant QProperty, QObjectBindableProperty, ou QObjectComputedProperty.
Les Q_PROPERTY sans BINDABLE peuvent également être liés et utilisés dans des expressions de liaison, à condition qu'ils définissent un signal NOTIFY. Vous devez envelopper la propriété dans un QBindable en utilisant le constructeur QBindable(QObject* obj, const char* property). Ensuite, la propriété peut être liée à l'aide de QBindable::setBinding() ou utilisée dans une expression de liaison à l'aide de QBindable::value(). Vous devez utiliser QBindable::value() dans les expressions de liaison au lieu de la fonction normale de la propriété READ (ou MEMBER) pour permettre le suivi des dépendances si la propriété n'est pas BINDABLE.
© 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.