Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Issue creating c++ object in qml and passing it to c++ function



  • 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 CustomObj

    customobj.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!


  • Moderators

    @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 a QObject* 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();
    }
    


  • @raven-worx Thanks, this solved my problem :)


Log in to reply