Enregistrer un pointer dans un QVariant¶
Introduction¶
Il est parfois intéressant d'enregistrer un pointeur dans un QVariant car tous les QObject peuvent stocker des propriétés au format QVariant.
En effet, il est plus simple de stocker un pointeur sur un objet A dans un objet B si celui-ci en a besoin plus tard plutôt que de gérer un container de pointeur avec une référence sur A et sur B (une QMap par exemple).
Un container de plus à gérer, c'est un peu plus fastidieux (il faut "boucler" pour retrouver le bon).
Le problème, c'est que Qt ne nous offre pas la possibilité d'enregistrer des pointeurs dans un QVariant.
Si vous sauvegardez un pointeur quelconque dans un QVariant, il vous sera retourné sous la forme d'un booléen.
Il faut donc ruser.
Démonstration par l'exemple¶
Pour qu'un QObject stocke un QVariant, il faut passer par la méthode bool QObject::setProperty ( const char * name, const QVariant & value ).
Exemple :
#include <QCoreApplication> #include <QObject> #include <QDebug> #include <QVariant> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QObject *myObject = new QObject(); myObject->setProperty("Solid", true); qDebug() << myObject->property("Solid").toBool(); return a.exec(); } // N'oubliez pas d'inclure le moc, nous déclarons tout dans un seul fichier (si vous avez des erreurs vtable) #include "main.moc" // Sortie Console // true
Il faut bien sûr connaitre le type de votre propriété pour avoir le bon résultat en retour. Ici, j'ai utilisé la méthode toBool() sur mon QVariant pour que la transformation se fasse correctement.
On va donc créer un mécanisme interne à une classe qui va nous permettre de transformer un pointeur en QVariant et vice-versa.
Reprenons notre exemple du dessus avec la déclaration d'une simple classe Example afin de pouvoir stocker un pointeur de cette classe dans un autre QObject.
#include <QCoreApplication> #include <QObject> #include <QDebug> #include <QVariant> class Example : public QObject { Q_OBJECT public: explicit Example(){;} }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Example *example = new Example(); qDebug() << example; QObject *myObject = new QObject(); // On essaye de ranger notre pointeur dans une "property" myObject->setProperty("monPointeurExample", example); return a.exec(); } #include "main.moc"
Si vous testez ce code, votre compilateur va vous dire :
'QVariant::QVariant(void)' is private*
Et oui, je vous ai dit que Qt ne nous permet pas de stocker des pointeurs... Vous en avez la preuve.
Pour contourner le problème, il faut "sérialiser" l'enregistrement du pointeur dans un QVariant mais aussi la récupération d'un QVariant en pointeur.
Nous allons donc définir une autre classe au-dessus de notre classe Example qui se chargera du travail de "sérialisation".
#include <QCoreApplication> #include <QObject> #include <QDebug> #include <QVariant> // Voici nous classe qui transforme un pointer en QVariant, et vice-versa template <class T> class ExamplePointer { public: /* Retourne le QVariant donné en paramètre sous la forme d'un pointeur */ static T* asPtr(QVariant v) { return (T *) v.value<void *>(); } /* Retourne le pointeur donné en paramètre sous la forme d'un QVariant */ static QVariant asQVariant(T* ptr) { return qVariantFromValue((void *) ptr); } }; class Example : public QObject { Q_OBJECT public: explicit Example(){;} }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Example *example = new Example(); QObject *myObject = new QObject(); // On enregistre notre pointeur en passant par la classe ExamplePointer myObject->setProperty("object", ExamplePointer<Example>::asQVariant(example)); // Pour récupérer notre pointeur Example *p1 = ExamplePointer<Example>::asPtr(myObject->property("object")); qDebug() << example; qDebug() << p1 ; return a.exec(); } #include "main.moc"
Vous devriez voir à l'exécution que les pointeurs example et p1 sont égaux.
Donc, ils indiquent la même adresse =) !
Nous avons réussi à enregistrer un pointeur sous la forme d'un QVariant, et ainsi pu utiliser le mécanisme les "properties" des QObject pour stocker notre pointeur.
Et voilà.
(Source : http://blog.bigpixel.ro/2010/04/storing-pointer-in-qvariant/)