Création de types Qt personnalisés
Présentation
Lorsqu'ils créent des interfaces utilisateur avec Qt, en particulier celles comportant des contrôles et des fonctionnalités spécialisés, les développeurs ont parfois besoin de créer de nouveaux types de données pouvant être utilisés en complément ou à la place des types de valeurs existants de Qt.
Les types standard tels que QSize, QColor et QString peuvent tous être stockés dans des objets QVariant, utilisés comme types de propriétés dans les classes basées sur QObject, et émis dans le cadre de la communication signal-slot.
Dans ce document, nous prenons un type personnalisé et décrivons comment l’intégrer au modèle objet de Qt afin qu’il puisse être stocké de la même manière que les types Qt standard. Nous montrons ensuite comment enregistrer ce type personnalisé pour permettre son utilisation dans les connexions de signaux et de slots.
Création d'un type personnalisé
Avant de commencer, nous devons nous assurer que le type personnalisé que nous créons répond à toutes les exigences imposées par QMetaType. En d’autres termes, il doit fournir :
- un constructeur par défaut public,
- un constructeur de copie public, et
- un destructeur public.
La définition suivante de la classe ` Message ` inclut ces membres :
class Message
{
public:
Message() = default;
~Message() = default;
Message(const Message &) = default;
Message &operator=(const Message &) = default;
Message(const QString &body, const QStringList &headers);
QStringView body() const;
QStringList headers() const;
private:
QString m_body;
QStringList m_headers;
};La classe fournit également un constructeur destiné à une utilisation normale et deux fonctions membres publiques qui servent à accéder aux données privées.
Déclaration du type avec QMetaType
La classe ` Message ` n'a besoin que d'une implémentation appropriée pour être utilisable. Cependant, le système de types de Qt ne sera pas en mesure de comprendre comment stocker, récupérer et sérialiser les instances de cette classe sans une aide supplémentaire. Par exemple, nous ne pourrons pas stocker les valeurs de ` Message ` dans ` QVariant`.
La classe de Qt chargée de gérer les types personnalisés est QMetaType. Pour faire connaître le type à cette classe, nous appelons la macro Q_DECLARE_METATYPE() sur la classe dans le fichier d'en-tête où elle est définie :
Q_DECLARE_METATYPE(Message);Il est désormais possible de stocker des valeurs de type ` Message ` dans des objets ` QVariant ` et de les récupérer ultérieurement :
QVariant stored;
stored.setValue(message);
...
Message retrieved = qvariant_cast<Message>(stored);
qDebug() << "Retrieved:" << retrieved;
retrieved = qvariant_cast<Message>(stored);
qDebug() << "Retrieved:" << retrieved;La macro ` Q_DECLARE_METATYPE()` permet également d'utiliser ces valeurs comme arguments des signaux, mais uniquement dans le cadre de connexions directes entre signaux et slots. Pour que ce type personnalisé puisse être utilisé de manière générale avec le mécanisme des signaux et des slots, il faut effectuer quelques opérations supplémentaires.
Création et destruction d'objets personnalisés
Bien que la déclaration de la section précédente rende le type utilisable dans les connexions signal-slot directes, il ne peut pas être utilisé pour les connexions signal-slot en file d’attente, telles que celles établies entre des objets situés dans des threads différents. En effet, le système de méta-objets ne sait pas comment gérer la création et la destruction d’objets de ce type personnalisé lors de l’exécution.
Pour permettre la création d’objets à l’exécution, appelez la fonction modèle ` qRegisterMetaType()` afin de l’enregistrer auprès du système de méta-objets. Cela rend également le type disponible pour les communications signal-slot en file d’attente, à condition que vous l’appeliez avant d’établir la première connexion utilisant ce type.
L’exemple « Queued Custom Type » déclare une classe ` Block ` qui est enregistrée dans le fichier ` main.cpp ` :
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
...
qRegisterMetaType<Block>();
...
return app.exec();
}Ce type est ensuite utilisé dans une connexion signal-slot dans le fichier window.cpp:
Window::Window(QWidget *parent)
: QWidget(parent), thread(new RenderThread(this))
{
...
connect(thread, &RenderThread::sendBlock,
this, &Window::addBlock);
...
setWindowTitle(tr("Queued Custom Type"));
}Si un type est utilisé dans une connexion en file d’attente sans avoir été enregistré, un avertissement s’affiche sur la console ; par exemple :
QObject::connect: Cannot queue arguments of type 'Block'
(Make sure 'Block' is registered using qRegisterMetaType().)Rendre le type imprimable
Il est souvent très utile de rendre un type personnalisé imprimable à des fins de débogage, comme dans le code suivant :
Message message(body, headers);
qDebug() << "Original:" << message;Pour ce faire, on crée un opérateur de flux pour le type, qui est souvent défini dans le fichier d'en-tête correspondant à ce type :
L'implémentation du type ` Message ` présentée ici s'efforce de rendre la représentation imprimable aussi lisible que possible :
QDebug operator<<(QDebug dbg, const Message &message)
{
QDebugStateSaver saver(dbg);
const QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts);
if (pieces.isEmpty())
dbg.nospace() << "Message()";
else if (pieces.size() == 1)
dbg.nospace() << "Message(" << pieces.first() << ")";
else
dbg.nospace() << "Message(" << pieces.first() << " ...)";
return dbg;
}La sortie envoyée au flux de débogage peut, bien sûr, être aussi simple ou aussi complexe que vous le souhaitez. Notez que la valeur renvoyée par cette fonction est l’objet QDebug lui-même, bien que celle-ci soit souvent obtenue en appelant la fonction membre maybeSpace() de QDebug, qui complète le flux avec des espaces pour le rendre plus lisible.
Pour en savoir plus
La documentation relative à la macro Q_DECLARE_METATYPE() et à la fonction qRegisterMetaType() contient des informations plus détaillées sur leurs utilisations et leurs limites.
L’exemple « Queued Custom Type » montre comment implémenter un type personnalisé avec les fonctionnalités décrites dans ce document.
Le document « Techniques de débogage » fournit un aperçu des mécanismes de débogage abordés ci-dessus.
© 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.