Before marking this as a duplicate of "Can't call slot or Q_INVOKABLE from QML in subclass of QQmlPropertyMap," please read the final response (https://stackoverflow.com/a/18674363/447438).
I am working on a design where I have a class (call it MyBaseClass) that inherits from QQmlPropertyMap. It implements some additional behaviors for my system which are then used by other classes that inerit from MyBaseClass (e.g. ChildClass).
From QML, (QtQuick), I wish to invoke a slot (mySlot()) of ChildClass. When I try, I get the following issues in the Application Output (mentioning MyBaseClass) even though I am only using ChildClass.
qrc:/main.qml:17: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
qrc:/main.qml:24: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
I also tried implementing sending signals from QML, but I get a similar issue trying to bind to the QML emitted signals. (I am not adding that example.)
For those suggesting I just inherit QQmlPropertyMap into ChildClass (in addition to MyBaseClass to which it already has the proper inheritance and intialization via the protected method), the result is not pretty:
/home/jwerner/Projects/InheritanceTest-simple/ChildClass.h:8: warning: direct base 'QQmlPropertyMap' is inaccessible due to ambiguity:
class ChildClass -> class MyBaseClass -> class QQmlPropertyMap
class ChildClass -> class QQmlPropertyMap
My "gut" says that the problem is I am not doing things the "Qt Way," but I can't figure out what it is.
Here is the minimum example code of the problem to demonstrate the problem. (I'm leaving out the .pro file since it is trivial to make.)
MyBaseClass.h
#include <QQmlPropertyMap>
class MyBaseClass : public QQmlPropertyMap
{
Q_OBJECT
public:
explicit MyBaseClass(QObject *parent = nullptr)
: QQmlPropertyMap(this, parent)
{}
};
ChildClass.h
#include "MyBaseClass.h"
#include <QObject>
#include <QDebug>
class ChildClass : public MyBaseClass
{
Q_OBJECT
public:
ChildClass(QObject *parent = nullptr)
: MyBaseClass(parent) {}
public slots:
void mySlot() {
qDebug() << "This is mySlot";
};
};
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: theMainWindow
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property QtObject cData: childData;
onCDataChanged: {
childData.mySlot();
}
Timer { // wait a bit before calling
repeat: false
interval: 2000
running: true
onTriggered: childData.mySlot();
}
}
main.cpp
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
auto childData = new ChildClass();
engine.rootContext()->setContextProperties({
QQmlContext::PropertyPair{"childData", QVariant::fromValue(childData)},
});
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}