0

My question is, does it possible to employ QQmlOpenMetaObject in the class and have method overloads of the class methods? I probably somehow used QQmlOpenMetaObject incorrectly or something but there is not much information about it anyway cause of private API, but I would really appreciate if someone could help me to figure out what is the problem in here. Also I created git repo if someone wants to build the example and play with it.

I am trying to use QQmlOpenMetaObject for my own purposes. Declaring a QQmlOpenMetaObject inside my class causes the function overloading behavior to break. Let's look at the normal behavior of the object:

// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myclass.h"
#include "myclasswithregularmetaobject.h"
#include "myclasswithcustommetaobject.h"

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

    if (true) {
        engine.rootContext()->setContextProperty("myObject", QVariant::fromValue(new MyClass));
    }
    if (false) {
        engine.rootContext()->setContextProperty("myObject", QVariant::fromValue(new MyClassWithRegularMetaObject));
    }
    if (false) {
        engine.rootContext()->setContextProperty("myObject", QVariant::fromValue(new MyClassWithCustomMetaObject));
    }
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}
// main.qml
import QtQuick 2.14
import QtQuick.Controls 2.14

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    Component.onCompleted: {
        // Call the no-argument function
        myObject.fire()

        // Call the function with a QJSValue argument
        var payload = { key: "value" }
        myObject.fire(payload)
    }
}
// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>
#include <QJSValue>
#include <QDebug>

class MyClass : public QObject {
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr)
        : QObject(parent) {}

    Q_INVOKABLE void fire() {
        qDebug() << "fire() called";
        // implementation for no arguments
    }

    Q_INVOKABLE void fire(const QJSValue& payload) {
        qDebug() << "fire(const QJSValue&) called with payload:" << payload.toString();
        // implementation for one argument
    }
};

#endif // MYCLASS_H

It works fine and give expected response:

fire() called
fire(const QJSValue&) called with payload: "[object Object]"

Declare QQmlOpenMetaObject in the class. This can be observed by an example:

// myclasswithregularmetaobject.h
#ifndef MYCLASSWITHREGULARMETAOBJECT_H
#define MYCLASSWITHREGULARMETAOBJECT_H

#include <QObject>
#include <QJSValue>
#include <QDebug>
#include <private/qqmlopenmetaobject_p.h>

class MyClassWithRegularMetaObject : public QObject
{
    Q_OBJECT
public:
    explicit MyClassWithRegularMetaObject(QObject *parent = nullptr)
        : QObject(parent)
        , m_metaObject(new QQmlOpenMetaObject(this))
    {}

    Q_INVOKABLE void fire() {
        qDebug() << "fire() called";
        // implementation for no arguments
    }

    Q_INVOKABLE void fire(const QJSValue& payload) {
        qDebug() << "fire(const QJSValue&) called with payload:" << payload.toString();
        // implementation for one argument
    }

private:
    QQmlOpenMetaObject *m_metaObject;
};

#endif // MYCLASSWITHREGULARMETAOBJECT_H

And it breaks overloaded functions. Now QML cannot see function with zero arguments but it sees that there is one with one argument.

qrc:/main.qml:11: Error: Insufficient arguments
3
  • Why should this work? Apparently you break the the meta object mechanism. Nobody can tell you what happens if you create your own instance of QQmlOpenMetaObject from MyClassWithRegularMetaObject. Maybe QQmlOpenMetaObject is implemented as a singleton and now the real meta object stops working. Maybe the meta object must be registered somewhere and now the wrong one is in the registry. Maybe the meta object must not be created in the constructor, but later lazily. Maybe by creating your own meta object, the real meta object is overwritten. There can only be one meta object and you have two.
    – habrewning
    Commented Jul 6 at 17:36
  • The problem is not that polymorphism doesn't work. If you call the methods from C++ it would work. The problem is that the meta object mechanism is (for whatever reason) corrupted, so that it does not know the two methods.
    – habrewning
    Commented Jul 6 at 18:06
  • Try to set m_metaObject in the body of the constructor and not in the initialisation list!
    – habrewning
    Commented Jul 6 at 18:07

0

Browse other questions tagged or ask your own question.