简体   繁体   中英

Passing an object from QML to C++

I am working on a simple app to demonstrate integration of C++ with QML but I have problems. In nutshell I want to create a C++ object in qml on fly and pass it to C++ for processing. Here is my code.

import QtQuick 2.4
import QtQuick.Window 2.2

import test 1.0

Window {
    visible: true
    MainForm {
        anchors.fill: parent

        mouseArea.onClicked: {

            console.log("clicked")

            var student = Qt.createComponent("Student")

            student.name = "Hello frome QML";

            console.log( student.name ) // good

            school.addStudent( student )

         }
   }
}

Student.h

#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
    QString m_name;

public:
    explicit Student(QObject *parent = 0);
    ~Student();

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

QString name() const
{
    return m_name;
}

signals:

void nameChanged(QString arg);

public slots:
void setName(QString arg)
{
    if (m_name == arg)
        return;

    m_name = arg;
    emit nameChanged(arg);
}
};

#endif // STUDENT_H

Now when I addStudent() to the school class, there is where there is trouble. The concern .cpp file below.

#include "school.h"
#include <QDebug>

School::School(QObject *parent) : QObject(parent)
{

}

School::~School()
{

}

// why does this not work? it cause compiler error..can't access private members of QObject
//void School::addStudent(Student student)
//{
////    students.append( &student );

////    qDebug() << "added";

////    qDebug() << student.name();// << " was added to school";
//}

void School::addStudent(Student * student)
{
    students.append( student );

    qDebug() << "added";

    qDebug() << student->name();// if this line is there, it breaks the application
}

The questions are also in comments inside the code but the summaries:

  1. Why does addStudent() crashes when I try to access student.name? I can access it though in the qml file after I set it.

  2. Why does my project not compile if I pass Student by value like seen in the code?

Additional thoughts

It seems like it may have to do with the C++ object getting destroyed by the time C++ function execute. What is the life cycle of C++ object created in QML? When does it gets destroyed? Could the lifetime of the object be an issue here?

Assume that you register the Student type to QML via qmlRegisterType in cpp file.

In your QML, Qt.createComponent("Student") does not create a Student object but a QQmlComponent . Try to set properties other than name and it still works since the object is not a Student . Instead, you should create an object from a pre-defined component via Component.createObject :

MainForm {
    id: mainForm
    mouseArea.onClicked: {
        var student = studentComponent.createObject(mainForm);
        student.name = "Hello frome QML";
        school.addStudent( student );
    }

    Component {
        id: studentComponent
        Student{}
    }
}

And everything works fine now.


Back to your code,

//QML
var student = Qt.createComponent("Student")
student.name = "Hello frome QML";
console.log( student.name ) // good

No, it's not good. student.abcdefg = "Hello from QML" works, too. Add console.log(student) and you can see that student is not a Student .

Why does addStudent() crashes when I try to access student.name? I can access it though in the qml file after I set it.

It crashed since the object passed from QML is not a pointer Student . QML engine passes a null pointer to this function. What you accessed in QML is not a Student .

Why does my project not compile if I pass Student by value like seen in the code?

Because Student is an QObject , which is not copyable. Pass by pointer instead.

What is the life cycle of C++ object created in QML? When does it gets destroyed? Could the lifetime of the object be an issue here?

The lifetime is not a issue in your QML since what you created is a component, not an object. When creating Student object in this answer,

var student = studentComponent.createObject(mainForm);

the newly created object sets mainForm as it's parent. The object won't be deleted until mainForm is released. Except you delete it explicitly.

Try moving the declaration of the function QString name() const in the declaration of class Student to before the Q_PROPERTY macro. Or specify "public:" again before the name function. The macro is resetting the access specifier to "private".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM