Creación de Tipos Qt Personalizados
Visión General
Cuando se crean interfaces de usuario con Qt, particularmente aquellas con controles y características especializadas, los desarrolladores a veces necesitan crear nuevos tipos de datos que puedan ser utilizados junto o en lugar del conjunto existente de tipos de valores de Qt.
Tipos estándar como QSize, QColor y QString pueden ser almacenados en objetos QVariant, usados como tipos de propiedades en clases basadas en QObject, y emitidos en comunicación de ranura de señal.
En este documento, tomamos un tipo personalizado y describimos cómo integrarlo en el modelo de objetos de Qt para que pueda ser almacenado de la misma forma que los tipos estándar de Qt. A continuación, mostramos cómo registrar el tipo personalizado para permitir su uso en conexiones de señales y ranuras.
Creación de un tipo personalizado
Antes de empezar, necesitamos asegurarnos de que el tipo personalizado que estamos creando cumple todos los requisitos impuestos por QMetaType. En otras palabras, debe proporcionar:
- un constructor público por defecto,
- un constructor público de copia, y
- un destructor público.
La siguiente definición de la clase Message incluye estos miembros:
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 clase también proporciona un constructor para uso normal y dos funciones miembro públicas que se utilizan para obtener los datos privados.
Declarar el tipo con QMetaType
La clase Message sólo necesita una implementación adecuada para ser utilizable. Sin embargo, el sistema de tipos de Qt no será capaz de entender cómo almacenar, recuperar y serializar instancias de esta clase sin algo de ayuda. Por ejemplo, no podremos almacenar valores de Message en QVariant.
La clase en Qt responsable de los tipos personalizados es QMetaType. Para dar a conocer el tipo a esta clase, invocamos la macro Q_DECLARE_METATYPE() sobre la clase en el fichero de cabecera donde está definida:
Q_DECLARE_METATYPE(Message);
Esto hace posible que los valores Message se almacenen en objetos QVariant y se recuperen más tarde:
QVariant stored; stored.setValue(mensaje); ... Mensaje recuperado = qvariant_cast<Mensaje>(stored);qDebug() << "Retrieved:" << retrieved; recuperado = qvariant_cast<Mensaje>(almacenado);qDebug() << "Retrieved:" << retrieved;
La macro Q_DECLARE_METATYPE() también hace posible que estos valores se utilicen como argumentos de señales, pero sólo en conexiones directas señal-ranura. Para que el tipo personalizado pueda utilizarse en general con el mecanismo de señales y ranuras, tenemos que realizar algún trabajo adicional.
Creación y destrucción de objetos personalizados
Aunque la declaración de la sección anterior hace que el tipo esté disponible para su uso en conexiones directas de ranura de señal, no se puede utilizar para conexiones de ranura de señal en cola, como las que se realizan entre objetos en diferentes subprocesos. Esto se debe a que el sistema de meta-objetos no sabe cómo manejar la creación y destrucción de objetos del tipo personalizado en tiempo de ejecución.
Para habilitar la creación de objetos en tiempo de ejecución, llame a la función de plantilla qRegisterMetaType() para registrarla en el sistema de meta-objetos. Esto también hace que el tipo esté disponible para la comunicación de ranura de señal en cola, siempre y cuando se llame antes de realizar la primera conexión que utilice el tipo.
El ejemplo del tipo personalizado en cola declara una clase Block que se registra en el archivo main.cpp:
int main(int argc, char *argv[]) { QApplication app(argc, argv); ... qRegisterMetaType<Block>(); ... return app.exec(); }
Este tipo se utiliza más tarde en una conexión de ranura de señal en el archivo 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 tipo se utiliza en una conexión en cola sin estar registrado, se imprimirá una advertencia en la consola; por ejemplo:
QObject::connect: Cannot queue arguments of type 'Block' (Make sure 'Block' is registered using qRegisterMetaType().)
Hacer imprimible el tipo
A menudo es bastante útil hacer imprimible un tipo personalizado para propósitos de depuración, como en el siguiente código:
Mensaje message(body, headers);qDebug() << "Original:" << message;
Esto se consigue creando un operador de flujo para el tipo, que a menudo se define en el fichero de cabecera de ese tipo:
La implementación para el tipo Message hace un esfuerzo para que la representación imprimible sea lo más legible posible:
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 salida enviada al flujo de depuración puede, por supuesto, hacerse tan simple o tan complicada como se desee. Tenga en cuenta que el valor devuelto por esta función es el propio objeto QDebug, aunque a menudo se obtiene llamando a la función miembro maybeSpace() de QDebug que rellena el flujo con caracteres de espacio para hacerlo más legible.
Lecturas adicionales
La documentación de la macro Q_DECLARE_METATYPE() y de la función qRegisterMetaType() contiene información más detallada sobre sus usos y limitaciones.
El ejemplo Queued Custom Type muestra cómo implementar un tipo personalizado con las características descritas en este documento.
El documento Técnicas de Depuración proporciona una visión general de los mecanismos de depuración discutidos anteriormente.
© 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.