Issue creating c++ object in qml and passing it to c++ function
-
wrote on 15 Jun 2018, 08:37 last edited by
Hello, this is my situation: i have a c++ class that i register as qml type and instantiate it in qml. Then i pass this through some qml Page where i populate this object; at last i want to bring this object back to c++ world.
Here is an example: i have this CustomObjcustomobj.h:
#include <QObject> #include <QMetaType> class CustomObj : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) public: explicit CustomObj(QObject *parent = nullptr); CustomObj(const CustomObj &other, QObject *parent = nullptr); QString name() const { return m_name; } void setName(const QString &newName); signals: void nameChanged(); public slots: private: QString m_name; }; Q_DECLARE_METATYPE(CustomObj)
customobj.cpp:
CustomObj::CustomObj(QObject *parent) : QObject(parent), m_name("test") { } CustomObj::CustomObj(const CustomObj &other, QObject *parent) : QObject(parent) { m_name = other.name(); } void CustomObj::setName(const QString &newName) { m_name = newName; }
it has only one attribute m_name setted in the constructor to show the issue.
I use a Manager to manage this object. Here is the code:manager.h:
#include <QObject> #include <iostream> #include "customobj.h" class Manager : public QObject { Q_OBJECT public: explicit Manager(QObject *parent = nullptr); Q_INVOKABLE void doSomething(const CustomObj &obj); signals: public slots: };
manager.cpp:
Manager::Manager(QObject *parent) : QObject(parent) { } void Manager::doSomething(const CustomObj &obj) { std::cout << obj.name().toStdString() << std::endl; }
not much to say here, just a function to show the problem.
In main.cpp i have registered the two objects:qmlRegisterType<Manager> ("Manager", 1, 0, "Manager"); qmlRegisterType<CustomObj> ("CustomObj", 1, 0, "CustomObj");
In main.qml i create the manager and start a stackview:
ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") Manager { id: myManager } StackView { id: stackView anchors.fill: parent initialItem: FirstView { } } }
In FirstView.qml i create the custom object and set the name attribute as user input:
Page { id: root TextField { id: myText anchors.centerIn: parent } CustomObj { id: myCustomObj name: myText.text } Button { id: nextButton anchors { top: myText.bottom horizontalCenter: parent.horizontalCenter margins: 20 } text: "Next" onClicked: { console.log(myCustomObj.name) root.StackView.view.push("qrc:/SecondView.qml", { myCustomObj: myCustomObj }) } } }
the output here is obviously correct and show what i have inserted
Here is the SecondView.qml:Page { id: root property CustomObj myCustomObj Button { id: doSomethingButton anchors.centerIn: parent text: "Do something" onClicked: { console.log(myCustomObj.name) myManager.doSomething(myCustomObj) } } }
The output is correct again, but the doSomethingFunction() won't print what i have inserted in TextField, but only "test". Using debugger i have noticed that once i pass myCustomObj to doSomething() method, a new CustomObj is created instead of using the existent one. Any suggestion about this behaviour?
I have found another way to do the same, but i would still understend why this happends.
Thanks! -
Hello, this is my situation: i have a c++ class that i register as qml type and instantiate it in qml. Then i pass this through some qml Page where i populate this object; at last i want to bring this object back to c++ world.
Here is an example: i have this CustomObjcustomobj.h:
#include <QObject> #include <QMetaType> class CustomObj : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) public: explicit CustomObj(QObject *parent = nullptr); CustomObj(const CustomObj &other, QObject *parent = nullptr); QString name() const { return m_name; } void setName(const QString &newName); signals: void nameChanged(); public slots: private: QString m_name; }; Q_DECLARE_METATYPE(CustomObj)
customobj.cpp:
CustomObj::CustomObj(QObject *parent) : QObject(parent), m_name("test") { } CustomObj::CustomObj(const CustomObj &other, QObject *parent) : QObject(parent) { m_name = other.name(); } void CustomObj::setName(const QString &newName) { m_name = newName; }
it has only one attribute m_name setted in the constructor to show the issue.
I use a Manager to manage this object. Here is the code:manager.h:
#include <QObject> #include <iostream> #include "customobj.h" class Manager : public QObject { Q_OBJECT public: explicit Manager(QObject *parent = nullptr); Q_INVOKABLE void doSomething(const CustomObj &obj); signals: public slots: };
manager.cpp:
Manager::Manager(QObject *parent) : QObject(parent) { } void Manager::doSomething(const CustomObj &obj) { std::cout << obj.name().toStdString() << std::endl; }
not much to say here, just a function to show the problem.
In main.cpp i have registered the two objects:qmlRegisterType<Manager> ("Manager", 1, 0, "Manager"); qmlRegisterType<CustomObj> ("CustomObj", 1, 0, "CustomObj");
In main.qml i create the manager and start a stackview:
ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") Manager { id: myManager } StackView { id: stackView anchors.fill: parent initialItem: FirstView { } } }
In FirstView.qml i create the custom object and set the name attribute as user input:
Page { id: root TextField { id: myText anchors.centerIn: parent } CustomObj { id: myCustomObj name: myText.text } Button { id: nextButton anchors { top: myText.bottom horizontalCenter: parent.horizontalCenter margins: 20 } text: "Next" onClicked: { console.log(myCustomObj.name) root.StackView.view.push("qrc:/SecondView.qml", { myCustomObj: myCustomObj }) } } }
the output here is obviously correct and show what i have inserted
Here is the SecondView.qml:Page { id: root property CustomObj myCustomObj Button { id: doSomethingButton anchors.centerIn: parent text: "Do something" onClicked: { console.log(myCustomObj.name) myManager.doSomething(myCustomObj) } } }
The output is correct again, but the doSomethingFunction() won't print what i have inserted in TextField, but only "test". Using debugger i have noticed that once i pass myCustomObj to doSomething() method, a new CustomObj is created instead of using the existent one. Any suggestion about this behaviour?
I have found another way to do the same, but i would still understend why this happends.
Thanks!@rigu10 said in Issue creating c++ object in qml and passing it to c++ function:
Q_INVOKABLE void doSomething(const CustomObj &obj);
first thing i noticed is that the signature of your doSomething() method is incorrect.
It should rather take aQObject*
parameter. This instance you can then cast to your custom type:void Manager::doSomething(QObject* obj) { if( CustomObj* c = qobject_cast<CustomObj*>(obj) ) qDebug() << c->name(); }
-
@rigu10 said in Issue creating c++ object in qml and passing it to c++ function:
Q_INVOKABLE void doSomething(const CustomObj &obj);
first thing i noticed is that the signature of your doSomething() method is incorrect.
It should rather take aQObject*
parameter. This instance you can then cast to your custom type:void Manager::doSomething(QObject* obj) { if( CustomObj* c = qobject_cast<CustomObj*>(obj) ) qDebug() << c->name(); }
wrote on 15 Jun 2018, 12:24 last edited by@raven-worx Thanks, this solved my problem :)
1/3