BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

Qt5 Tutorial QVariant and QMetaType - 2020





Bookmark and Share





bogotobogo.com site search:




QVariant

In this tutorial, we will learn about QVariant.

The Qt QVariant Class doc says:

The QVariant class acts like a union for the most common Qt data types.

Because C++ forbids unions from including types that have non-default constructors or destructors, most interesting Qt classes cannot be used in unions. Without QVariant, this would be a problem for QObject::property() and for database work, etc.

A QVariant object holds a single value of a single type() at a time. (Some type()s are multi-valued, for example a string list.) You can find out what type, T, the variant holds, convert it to a different type using convert(), get its value using one of the toT() functions (e.g., toSize()) and check whether the type can be converted to a particular type using canConvert().

The methods named toT() (e.g., toInt(), toString()) are const. If you ask for the stored type, they return a copy of the stored object. If you ask for a type that can be generated from the stored type, toT() copies and converts and leaves the object itself unchanged. If you ask for a type that cannot be generated from the stored type, the result depends on the type; see the function documentation for details.

The code below is doing serialization and QVariant is being used for the variable v.

#include <QCoreApplication>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QStringList>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "Writing...";
    QFile file("C:/TEST/file.txt");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file;);   // we will serialize the data into the file

    QVariant v(123);                // The variant now contains an int
    int x = v.toInt();              // x = 123
    out << v;                       // Writes a type tag and an int to out
    qDebug() << v;
    v = QVariant("hello");          // The variant now contains a QByteArray
    v = QVariant(QObject::tr("hello"));      // The variant now contains a QString
    int y = v.toInt();              // y = 0 since v cannot be converted to an int
    QString s = v.toString();       // s = tr("hello")  (see QObject::tr())
    out << v;
    qDebug() << v;
    file.flush();
    file.close();

    qDebug() << "Reading...";
    file.open(QIODevice::ReadOnly);
    QDataStream in(&file;);          // (opening the previously written stream)
    in >> v;                        // Reads an Int variant
    int z = v.toInt();              // z = 123
    qDebug() << v;

    in >> v;

    // just checking the possibility
    // does not guarantee the valid conversion
    if(v.canConvert<QStringList>()) {
        qDebug() << v.toStringList();
    }

    file.close();

    return a.exec();
}

Output:

Writing...
QVariant(int, 123)
QVariant(QString, "hello")
Reading...
QVariant(int, 123)
("hello")

We did the serialization successfully!



A Note on GUI Types:

Because QVariant is part of the Qt Core module, it cannot provide conversion functions to data types defined in Qt GUI, such as QColor, QImage, and QPixmap.





QVariant with Custom Types (class, struct, etc.)

Will the QVariant work with custom types such as class?

Let's look at the following code which want to get the class member from QVariant.

#include <QCoreApplication>
#include "myclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MyClass mClass;
    QVariant v = QVariant::fromValue(mClass);

    return a.exec();
}

In the code, we used QVariant QVariant::fromValue(const T & value).
It returns a QVariant containing a copy of value. Behaves exactly like setValue() otherwise.

As an example, we can use it this way:

MyCustomStruct s;
return QVariant::fromValue(s);

When we compile it, we get the following message:

Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system.

So, it sounds like our class is not registered for meta-object system.

What is MetaType?

Let's look up the Qt doc, QMetaTeyp Class:

The QMetaType class manages named types in the meta-object system.

The class is used as a helper to marshall types in QVariant and in queued signals and slots connections. It associates a type name to a type so that it can be created and destructed dynamically at run-time. Declare new types with Q_DECLARE_METATYPE() to make them available to QVariant and other template-based functions.

Call qRegisterMetaType() to make type available to non-template based functions, such as the queued signal and slot connections.

Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered.

The doc also provides some code to allocates and destructs an instance of MyClass::

int id = QMetaType::type("MyClass");
if (id != QMetaType::UnknownType) {
    void *myClassPtr = QMetaType::create(id);
    ...
    QMetaType::destroy(id, myClassPtr);
    myClassPtr = 0;
}

So, looks like we need to register our class:

// myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H
#include <QMetaType>
#include <QString>

class MyClass
{
public:
    MyClass();
    QString mName;
};

Q_DECLARE_METATYPE(MyClass)
#endif // MYCLASS_H

Here is the description about the MetaType declaration:

Q_DECLARE_METATYPE(Type)

This macro makes the type Type known to QMetaType as long as it provides a public default constructor, a public copy constructor and a public destructor. It is needed to use the type Type as a custom type in QVariant.

This macro requires that Type is a fully defined type at the point where it is used. For pointer types, it also requires that the pointed to type is fully defined. Use in conjunction with Q_DECLARE_OPAQUE_POINTER() to register pointers to forward declared types.

Ideally, this macro should be placed below the declaration of the class or struct. If that is not possible, it can be put in a private header file which has to be included every time that type is used in a QVariant.

Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant. Note that if you intend to use the type in queued signal and slot connections or in QObject's property system, you also have to call qRegisterMetaType() since the names are resolved at runtime.

This example shows a typical use case of Q_DECLARE_METATYPE():

struct MyStruct
{
    int i;
    ...
};

Q_DECLARE_METATYPE(MyStruct)

If MyStruct is in a namespace, the Q_DECLARE_METATYPE() macro has to be outside the namespace:

namespace MyNamespace
{
    ...
}

Q_DECLARE_METATYPE(MyNamespace::MyStruct)

Since MyStruct is now known to QMetaType, it can be used in QVariant:

MyStruct s;
QVariant var;
var.setValue(s); // copy s into the variant

...

// retrieve the value
MyStruct s2 = var.value<MyStruct>();



Back to our example.

If we run our code again, now it compiles successfully since we've been registered.

But we want to check if it really works. We set one member of the class and put the class into QVariant. Then, we try to get it back from QVariant.

Here is main.cpp:

#include <QCoreApplication>
#include <QDebug>
#include "myclass.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MyClass mClass;
    mClass.name = "Debussy";
    
    // put a class into QVariant
    QVariant v = QVariant::fromValue(mClass);
    
    // What's the type?
    // It's MyClass, and it's been registered 
    // by adding macro in "myclass.h"
    MyClass vClass = v.value<MyClass>();

    qDebug() << vClass.name;  

    return a.exec();
}

Output:

"Debussy"

We got it.















Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong






Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Qt 5 Tutorial



Hello World

Signals and Slots

Q_OBJECT Macro

MainWindow and Action

MainWindow and ImageViewer using Designer A

MainWindow and ImageViewer using Designer B

Layouts

Layouts without Designer

Grid Layouts

Splitter

QDir

QFile (Basic)

Resource Files (.qrc)

QComboBox

QListWidget

QTreeWidget

QAction and Icon Resources

QStatusBar

QMessageBox

QTimer

QList

QListIterator

QMutableListIterator

QLinkedList

QMap

QHash

QStringList

QTextStream

QMimeType and QMimeDatabase

QFile (Serialization I)

QFile (Serialization II - Class)

Tool Tips in HTML Style and with Resource Images

QPainter

QBrush and QRect

QPainterPath and QPolygon

QPen and Cap Style

QBrush and QGradient

QPainter and Transformations

QGraphicsView and QGraphicsScene

Customizing Items by inheriting QGraphicsItem

QGraphicsView Animation

FFmpeg Converter using QProcess

QProgress Dialog - Modal and Modeless

QVariant and QMetaType

QtXML - Writing to a file

QtXML - QtXML DOM Reading

QThreads - Introduction

QThreads - Creating Threads

Creating QThreads using QtConcurrent

QThreads - Priority

QThreads - QMutex

QThreads - GuiThread

QtConcurrent QProgressDialog with QFutureWatcher

QSemaphores - Producer and Consumer

QThreads - wait()

MVC - ModelView with QListView and QStringListModel

MVC - ModelView with QTreeView and QDirModel

MVC - ModelView with QTreeView and QFileSystemModel

MVC - ModelView with QTableView and QItemDelegate

QHttp - Downloading Files

QNetworkAccessManager and QNetworkRequest - Downloading Files

Qt's Network Download Example - Reconstructed

QNetworkAccessManager - Downloading Files with UI and QProgressDialog

QUdpSocket

QTcpSocket

QTcpSocket with Signals and Slots

QTcpServer - Client and Server

QTcpServer - Loopback Dialog

QTcpServer - Client and Server using MultiThreading

QTcpServer - Client and Server using QThreadPool

Asynchronous QTcpServer - Client and Server using QThreadPool

Qt Quick2 QML Animation - A

Qt Quick2 QML Animation - B

Short note on Ubuntu Install

OpenGL with QT5

Qt5 Webkit : Web Browser with QtCreator using QWebView Part A

Qt5 Webkit : Web Browser with QtCreator using QWebView Part B

Video Player with HTML5 QWebView and FFmpeg Converter

Qt5 Add-in and Visual Studio 2012

Qt5.3 Installation on Ubuntu 14.04

Qt5.5 Installation on Ubuntu 14.04

Short note on deploying to Windows




Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong













Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master