Custom Type Example#
The Custom Type example shows how to integrate a custom type into Qt’s meta-object system.
Qt provides a range of standard value types that are used to provide rich and meaningful APIs. These types are integrated with the meta-object system, enabling them to be stored in
QVariant objects, written out in debugging information and sent between components in signal-slot communication.
Custom types can also be integrated with the meta-object system as long as they are written to conform to some simple guidelines. In this example, we introduce a simple
Message class, we describe how we make it work with
QVariant , and we show how it can be extended to generate a printable representation of itself for use in debugging output.
The Message Class Definition#
Message class is a simple value class that contains two pieces of information (a
QString and a
QStringList ), each of which can be read using trivial getter functions:
class Message(): # public Message() = default ~Message() = default Message(Message ) = default Message operator=(Message ) = default Message(QString body, QStringList headers) body = QStringView() headers = QStringList() # private m_body = QString() m_headers = QStringList()
The default constructor, copy constructor and destructor are all required, and must be public, if the type is to be integrated into the meta-object system. Other than this, we are free to implement whatever we need to make the type do what we want, so we also include a constructor that lets us set the type’s data members.
To enable the type to be used with
QVariant , we declare it using the
We do not need to write any additional code to accompany this macro.
To allow us to see a readable description of each
Message object when it is sent to the debug output stream, we define a streaming operator:
operator<< = QDebug(QDebug dbg, Message message)
This facility is useful if you need to insert tracing statements in your code for debugging purposes.
The Message Class Implementation#
The streaming operator is implemented in the following way:
operator<< = QDebug(QDebug dbg, Message message) saver = QDebugStateSaver(dbg) pieces = message.body().split(u"\r\n", Qt.SkipEmptyParts) if (pieces.isEmpty()) dbg.nospace() << "Message()" elif pieces.size() == 1: dbg.nospace() << "Message(" << pieces.first() << ")" else: dbg.nospace() << "Message(" << pieces.first() << " ...)" return dbg
Here, we want to represent each value depending on how many lines are stored in the message body. We stream text to the
QDebug object passed to the operator and return the
QDebug object obtained from its maybeSpace() member function; this is described in more detail in the Creating Custom Qt Types document.
We include the code for the getter functions for completeness:
def body(self): return m_body def headers(self): return m_headers
With the type fully defined, implemented, and integrated with the meta-object system, we can now use it.
Using the Message#
In the example’s
main() function, we show how a
Message object can be printed to the console by sending it to the debug stream:
message = Message(body, headers) print("Original:", message)
You can use the type with
QVariant in exactly the same way as you would use standard Qt value types. Here’s how to store a value using the
stored = QVariant() stored.setValue(message)
fromValue() function can be used if you are using a compiler without support for member template functions.
The value can be retrieved using the
value() member template function:
retrieved = qvariant_cast<Message>(stored) print("Retrieved:", retrieved) retrieved = qvariant_cast<Message>(stored) print("Retrieved:", retrieved)
Message type can also be used with direct signal-slot connections.
To register a custom type for use with queued signals and slots, such as those used in cross-thread communication, see the Queued Custom Type Example .
More information on using custom types with Qt can be found in the Creating Custom Qt Types document.