2
votes

I have problems receiving the signal mySignal with the correct enum type in qml. I think I have done everything right:

  • The enum is in a separate class, derived from QObject
  • The enum is registered with Q_ENUMS
  • The class containing enum is registered with qmlRegisterUncreatableType
  • The class the signal is defined in, is also a QObject and also registered with qmlRegisterUncreatableType

Notable facts:

  • Running the program prints the log in the slot called from main.qml, but the signal emitted is not received in qml.
  • Uncommenting the emit in textclass.cpp allows the signal to be received in QML, but the comparison with the enum value is not triggered as it should be.

Why do I not recieve the signal with the enum up in QML and why cannot I compare to the enum value in QML even though is is exposed with Q_ENUMS?

I have seen a defect report regarding enums on the Qt defect page, so I understand that the support for enums in Qt is not rock solid. However, I really would like to be able to compare values to enums up in QML for signals received and at the moment I am not. For some reason the value entered into mySlot gladly accepts the same enum value that is not recognized in the signal handler. Code listings below.

Qt 5.4 on Ubuntu was used.

error.h:

#ifndef ERROR_H
#define ERROR_H

#include <QObject>
#include <QtQml>

class Error : public QObject
{
    Q_OBJECT
    Q_ENUMS(Type)

public:
    explicit Error(QObject *parent = 0) {Q_UNUSED(parent)};
    ~Error() {};

    static void RegisterTypes(void)
    {
        qmlRegisterUncreatableType<Error>("Types", 1, 0, "Error", "Error class uncreatable");
    }

    enum Type {
        OK = 0,
        FILE_ERROR
    };
};

#endif // ERROR_H

testclass.h:

#ifndef TESTCLASS_H
#define TESTCLASS_H

#include <QObject>
#include <QVariant>
#include <QDebug>

#include "error.h"

class TestClass : public QObject
{
    Q_OBJECT

public:
    explicit TestClass(QObject *parent = 0);
    ~TestClass();

    static void RegisterTypes(void)
    {
        qmlRegisterUncreatableType<TestClass>("TestClass", 1, 0, "TestClass", "TestClass uncreatable");
    };

signals:
    void mySignal(Error::Type arg);
    void mySignal(int arg);

public slots:
    void mySlot(QVariant arg);
};

#endif // TESTCLASS_H

testclass.cpp:

#include "testclass.h"

TestClass::TestClass(QObject *parent) : QObject(parent)
{

}

TestClass::~TestClass()
{

}

void TestClass::mySlot(QVariant arg)
{
    qDebug() << "mySlot called" << arg.toInt();
    int retval = static_cast<int>(arg.toInt());
    emit mySignal(static_cast<Error::Type>(retval));
    //   emit mySignal(retval);
}

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>

#include "error.h"
#include "testclass.h"

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

    Error::RegisterTypes();
    TestClass::RegisterTypes();

    TestClass* tPtr = new TestClass();

    engine.rootContext()->setContextProperty("_t", tPtr);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

main.qml:

import QtQuick 2.4
import QtQuick.Window 2.2
import Types 1.0
import TestClass 1.0

Window {
    visible: true
    width: button.width + 20
    height: button.height + 20
    Rectangle {
        id: button
        width: theText.width + 20
        height: theText.height + 20
        anchors.margins: 10
        anchors.centerIn: parent
        border.width: 3

        Connections {
            target: _t

            onMySignal: {
                console.log("onMySignal: ", arg)
                if (arg == Error.OK) {
                    console.log("OK")
                }
                else if (arg == Error.FILE_ERROR) {
                    console.log("FILE_ERROR")
                }
                else {
                    console.log("UNDEFINED")
                }
            }
        }

        Text {
            id: theText
            anchors.centerIn: parent
            text: "press me!"
            font.pixelSize: 30
        }

        MouseArea {
            anchors.fill: parent
            onClicked: _t.mySlot(Error.FILE_ERROR)
            onPressed: button.scale = 0.9
            onReleased: button.scale = 1.0
        }
    }
}
1
You overload mySignal wich is not suported by QML, but I cannot find anything about it in documentation.Arpegius
Yes, I know. it does not work if it is removed either though. File.Error is supplied in the slot, undefined is returned to QML if I remove the int prototype.reprazent74

1 Answers

2
votes

The problems to this was two-fold.

First problem:

  • Error::Type was not registered within the Meta type system, the following line needs to be added after the Error class declaration:

    Q_DECLARE_METATYPE(Error::Type)

Second problem:

  • Was that I had selected the name 'Error' for the Error class when I registered it. This clashed with a built in type. The registration needs to be changed to this:

    qmlRegisterUncreatableType("Types", 1, 0, "ErrorClass", "Error class uncreatable");

    (The QML code would also need to be updated to reflect this of course.)

Changing these two things solved the problem, and the signal can now correctly be received in QML-code.