Calling function from object of object in QML results in TypeError
-
I'm trying to connect a function of a C++ object of another C++ object to my QML UI. The first C++ object lives in a separate QThread. The structure is as follows:
- main.qml
- main.cpp
- Base class, QThread
- Hardware class
- Base class, QThread
Which means that the Hardware class is just an object created in the QThread Base.
I would like to connect my QML UI to the functions of the Hardware class. So I set the context property:
Base* base = new Base(argc, argv); engine.rootContext()->setContextProperty("base", base);
I was not able to connect to the functions of the Hardware class, e.g.
onClicked: base.hardware.resetSystem()
fails with
qrc:/SideBarForm.ui.qml:95: TypeError: Cannot call method 'resetSystem' of undefined
But I can successfully call functions of the base class, e.g.
onClicked: base.test()
And calling the function from main.cpp works also fine:
base->hardware->resetSystem();
Furthermore, hardware is public in Base and resetSystem() is a public slot in Hardware:
public: std::shared_ptr<Hardware> hardware;
--
public slots: void resetSystem();
What is the proper way of connecting signals and slots from "sub-objects" in QThreads to a QML interface?
-
I'm trying to connect a function of a C++ object of another C++ object to my QML UI. The first C++ object lives in a separate QThread. The structure is as follows:
- main.qml
- main.cpp
- Base class, QThread
- Hardware class
- Base class, QThread
Which means that the Hardware class is just an object created in the QThread Base.
I would like to connect my QML UI to the functions of the Hardware class. So I set the context property:
Base* base = new Base(argc, argv); engine.rootContext()->setContextProperty("base", base);
I was not able to connect to the functions of the Hardware class, e.g.
onClicked: base.hardware.resetSystem()
fails with
qrc:/SideBarForm.ui.qml:95: TypeError: Cannot call method 'resetSystem' of undefined
But I can successfully call functions of the base class, e.g.
onClicked: base.test()
And calling the function from main.cpp works also fine:
base->hardware->resetSystem();
Furthermore, hardware is public in Base and resetSystem() is a public slot in Hardware:
public: std::shared_ptr<Hardware> hardware;
--
public slots: void resetSystem();
What is the proper way of connecting signals and slots from "sub-objects" in QThreads to a QML interface?
@prex one simple way is to add a Q_INVOKABLE method (or public slot) to Base
Q_INVOKABLE void resetHardwareSys(){ hardware->resetSystem(); }
or you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )
-
@prex one simple way is to add a Q_INVOKABLE method (or public slot) to Base
Q_INVOKABLE void resetHardwareSys(){ hardware->resetSystem(); }
or you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )
@LeLev Thanks, this works now. So the first solution means going over two public slots. I'm wondering about how to handle signals from C++ to QML then. First using QObject::connect() and then the Connections QML type? I have lots of data from the Hardware class which I need to visualize in the UI.
I was reading many posts about signals & slots not working between QML and QThreads. I'm a little bit confused since it seems to work here...
-
I like the Q_PROPERTY approach in general but I don't understand what you mean by
@LeLev said in Calling function from object of object in QML results in TypeError:
you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )
At the moment I have different Q_PROPERTIES defined in my Hardware class, but how can I make them accessible by QML? Or do you mean adding a Q_PROPERTY for the whole Hardware class?
-
I like the Q_PROPERTY approach in general but I don't understand what you mean by
@LeLev said in Calling function from object of object in QML results in TypeError:
you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )
At the moment I have different Q_PROPERTIES defined in my Hardware class, but how can I make them accessible by QML? Or do you mean adding a Q_PROPERTY for the whole Hardware class?
@prex said in Calling function from object of object in QML results in TypeError:
you mean adding a Q_PROPERTY for the whole Hardware class?
yes,
for the getter method, don't return the hardware object directly, use QVariant::fromValue to return it as a QVariant -
@prex said in Calling function from object of object in QML results in TypeError:
you mean adding a Q_PROPERTY for the whole Hardware class?
yes,
for the getter method, don't return the hardware object directly, use QVariant::fromValue to return it as a QVariant -
@LeLev I‘m not sure if I understand correctly. Should I do something like
Q_PROPERTIES(Hardware hardware ...)
in Base? But how to access this then? Can you please elaborate a little bit more on it?
@prex hi
class Hardware : public QObject { Q_OBJECT public: explicit Hardware (QObject *parent = nullptr); public slots: void write(const QString &str){ qDebug()<< str; } };
class Example : public QObject { Q_OBJECT Q_PROPERTY( Hardware * hardware READ hardware NOTIFY hardwareChanged) public: explicit Example(QObject *parent = nullptr); Hardware * hardware (){ return m_hardware; } signals: void hardwareChanged(); private: Hardware *m_hardware; };
Example e; engine.rootContext()->setContextProperty("obj",&e);
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Component.onCompleted: obj.hardware.write("hello") }
-
@prex hi
class Hardware : public QObject { Q_OBJECT public: explicit Hardware (QObject *parent = nullptr); public slots: void write(const QString &str){ qDebug()<< str; } };
class Example : public QObject { Q_OBJECT Q_PROPERTY( Hardware * hardware READ hardware NOTIFY hardwareChanged) public: explicit Example(QObject *parent = nullptr); Hardware * hardware (){ return m_hardware; } signals: void hardwareChanged(); private: Hardware *m_hardware; };
Example e; engine.rootContext()->setContextProperty("obj",&e);
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Component.onCompleted: obj.hardware.write("hello") }