Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ENUMS from different classes (or namespaces) for slots called from QML

Tags:

enums

qt

qt5

qml

I have a class (e.g. MyEnumClass, Q_GADGET) in which I define an enum, e.g. MyEnum.
I call Q_ENUM(MyEnum) to register it to the metaobject, and register the whole class as uncreatable type to QML.

In my second class (MyObject : QObject with macro Q_OBJECT) I have a slot that consumes a MyEnum as parameter. This object is registered as regular type to QML (creatable).

I want to call the slot from QML with a value from MyEnum - this fails, as the Type MyEnumClass::MyEnum seems to be unknown.

When the enum is defined inside the class with the slot, it works fine.


MVCE

class MyEnumClass {
    Q_GADGET
public:
    enum MyEnum {
        E1,
        E2,
        E3
    };
    Q_ENUM(MyEnum)
};


class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject(QObject* parent = nullptr) : QObject(parent) {}

    enum TestEnum {
        V1,
        V2,
        V3
    };
    Q_ENUM(TestEnum)

public slots:
    void testFun1(MyEnumClass::MyEnum val) { qDebug() << val; }
    void testFun2(TestEnum val) { qDebug() << val; }
};

in main.cpp:

qmlRegisterUncreatableType<MyEnumClass>("MyObject", 1, 0, "MyEnum", "Uncreatable");
qmlRegisterType<MyObject>("MyObject", 1, 0, "MyObject");

in main.qml:

import MyObject 1.0
ApplicationWindow {
    id: window
    visible: true
    width: 600
    height: 600

    MyObject {
        id: obj
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            console.log(MyObject.V2)
            console.log(MyEnum.E2)
            obj.testFun2(MyObject.V2)
            obj.testFun1(MyEnum.E1)
        }
    }
}

I tried to inherit MyEnumClass in MyObject to make the enum part of MyObject, I tried with different macros and functions to make the enum even more available in the MetaObjectSystem... to no avail.

I also tried to put an enum in a namespace as described here - it was also unusable for a slot.

The only way I found to have the slot called, was by removing the enum and using int as type for the parameter - which is not that nice...


How can I make this work?
Are there any tricks I am missing?

like image 350
derM Avatar asked Jun 13 '18 10:06

derM


1 Answers

Register metatype:

qRegisterMetaType<MyEnumClass::MyEnum>();

Explanation:

From Q_ENUM( ...) documentation:

This macro registers an enum type with the meta-object system. It must be placed after the enum declaration in a class that has the Q_OBJECT or the Q_GADGET macro. For namespaces use Q_ENUM_NS() instead.

...

Registered enumerations are automatically registered also to the Qt meta type system, making them known to QMetaType without the need to use Q_DECLARE_METATYPE().

Using Q_ENUM automatically registers enum with meta-object system so you don't need to add Q_DECLARE_METATYPE(MyEnum)

But to use enum in queued signal slot connections, properties... you need to register meta type.

As said in int qRegisterMetaType() documentation:

To use the type T in QVariant, using Q_DECLARE_METATYPE() is sufficient. To use the type T in queued signal and slot connections, qRegisterMetaType() must be called before the first connection is established.

Also, to use type T with the QObject::property() API, qRegisterMetaType() must be called before it is used, typically in the constructor of the class that uses T, or in the main() function.

like image 54
Eligijus Pupeikis Avatar answered Oct 09 '22 00:10

Eligijus Pupeikis