9

I need to assign a pointer to a custom class in qml using QQmlContext::setContextProperty(). Another qml object has Q_PROPERTY of the same type to retrieve it again.

A simple test showed me that the conversion does not work like i thought.

#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>

class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};

Q_DECLARE_METATYPE(TestClass*)

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

    qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();

    auto testObject = new TestClass;
    QVariant variant(qMetaTypeId<TestClass*>(), testObject);
    auto test = variant.value<TestClass*>();

    qDebug() << testObject << variant << test;

    return 0;
}

This tiny test application gives me an output like this:

metaTypeId = 1024
TestClass::TestClass()
0x1b801e0 QVariant(TestClass*, ) 0x0

I would really like to get the same pointer out again after converting it down to a QVariant. Later I will assign it to a qml context and then the conversation must work correctly.

feedc0de
  • 3,646
  • 8
  • 30
  • 55
  • [`QVariant::value`](http://doc.qt.io/qt-5/qvariant.html#value): *If the pointer stored in the QVariant can be qobject_cast to T, then that result is returned. Otherwise a null pointer is returned. Note that this only works for QObject subclasses which use the Q_OBJECT macro.* If you want to store a pointer in `QVariant`, you have to store it as `void*`. – thuga Jun 12 '17 at 14:01
  • If I would use void* as QVariant-Type, can the `Q_PROPERTY` for interfacing with qml still be a `TestClass*`? I cannot add the Q_OBJECT macro to the class i want to transport through qml, because the class was not written by me. – feedc0de Jun 12 '17 at 14:12
  • What is the goal of passing an object to QML which is not designed for it? – m7913d Jun 18 '17 at 20:30
  • I need to pass it to multiple custom c++ QuickItem. It is the pointer to my data model. – feedc0de Jun 20 '17 at 07:14

2 Answers2

13

This works for me using Qt 5.9:

#include <QVariant>
#include <QDebug>

class CustomClass
{
public:
    CustomClass()
    {
    }
};    
Q_DECLARE_METATYPE(CustomClass*)

class OtherClass
{
public:
    OtherClass()
    {
    }
};
Q_DECLARE_METATYPE(OtherClass*)

int main()
{
    CustomClass *c = new CustomClass;
    OtherClass *o = new OtherClass;
    QVariant v;
    v.setValue(c);
    QVariant v2;
    v2.setValue(o);

    qDebug() << v.userType() << qMetaTypeId<CustomClass*>() << v2.userType() << qMetaTypeId<OtherClass*>();
    qDebug() << v.value<CustomClass*>() << c << v2.value<OtherClass*>() << o;

    return 0;
}

And the output i got:

1024 1024 1025 1025
0x81fca50 0x81fca50 0x81fca60 0x81fca60
thuga
  • 12,601
  • 42
  • 52
5

As @thuga mentioned in the comments, you need to use void* and static_cast along with QVariant::fromValue.

#include <QCoreApplication>
#include <QDebug>
#include <QMetaType>

class TestClass
{
public: TestClass() { qDebug() << "TestClass()::TestClass()"; }
};

Q_DECLARE_METATYPE(TestClass*)

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

    qDebug() << "metaTypeId =" << qMetaTypeId<TestClass*>();

    auto testObject = new TestClass;
    QVariant variant(QVariant::fromValue(static_cast<void*>(testObject)));
    auto test = static_cast<TestClass*>(variant.value<void*>());

    qDebug() << testObject << variant << test;

    return 0;
}
Silas Parker
  • 8,017
  • 1
  • 28
  • 43