yudjin yudjin - 1 year ago 203
C++ Question

Enum in Qt property

I have a code, which works with Qt 5.5 and doesn't with Qt 5.2. Problem is with this enum:

#include <QtCore/QMetaType>
enum Area
{
Area_A,
Area_B,
Area_C
};

Q_DECLARE_METATYPE(Area)


Then I have an object, which exposes this area property:

class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Area area READ area WRITE setArea NOTIFY areaChanged)
public:
explicit MyClass(QObject *parent = 0)
: QObject(parent), m_area(Area_A){}

Area area() const { return m_area; }
void setArea(Area area) {
m_area = area;
emit areaChanged(area);
}

signals:
void areaChanged(Area area);
private:
Area m_area;
};


And main.cpp:

#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <QtQml/QtQml>
#include "MyClass.h"

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

qmlRegisterType<MyClass>("GLib", 1, 0, "MyClass");

MyClass controller;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("controller", &controller);
engine.load("./main.qml");

controller.setArea(Area_B);
return app.exec();
}


It compiles, everything is OK. But when I tried to use area property in qml:

import QtQuick 2.0
import QtQuick.Window 2.0
import GLib 1.0

Window {
visible: true
id: root

property int area: controller.area

Text {
id: name
text: "Test"
x: area * 30
y: area * 30
}
}


I have run-time errors, if Qt 5.2 is used (Linux, x64):


QMetaProperty::read: Unable to handle unregistered datatype 'Area' for
property 'MyClass::area'
file:///home/yech844/devel/test_qml/main.qml:10:24: Unable to assign
[undefined] to int QMetaProperty::read: Unable to handle unregistered
datatype 'Area' for property 'MyClass::area'
file:///home/yech844/devel/test_qml/main.qml:10:24: Unable to assign
[undefined] to int


Is it a bug in Qt? Why I can't use Enum, which is declared out of Class scope?

Answer Source

I don't know why the code works in Qt 5.5, but I know why it doesn't in Qt 5.2.

Q_DECLARE_METATYPE(...) only makes the type available in static (compiled) context. For example, if you want to use the type in QVariant::fromValue(...). Here, the type you pass to the function can be processed during compile time, and for this, Q_DECLARE_METATYPE is enough.

However, if you want to use a type in a pure runtime context, for example in a QML document, the Qt runtime doesn't know the type declared with Q_DECLARE_METATYPE. For this, a function call (evaluated during runtime) needs to be made, and qRegisterMetatype is the tool for this:

qRegisterMetaType<Area>("Area");

My guess for Qt 5.5 not needing that line is that qmlRegisterType might detect the use of the meta type in the property and automatically calls the above function for you.