Jacob Krieg
Jacob Krieg

Reputation: 3184

Dynamically create C++ object from QML

I want to dynamically create a C++ object from QML. I created a QObject derived class named Car and exposed it to QML using qmlRegisterType<Car>("org.qtproject.models", 1, 0, "Car");. Inside QML I am able to instantiate a Car object like this:

Car {
    id : car_1
    carName : "H1"
    carBrand : "Hummer"
    carPrice : 125000
} 

and then use the car_1 object and pass it back to C++ with ease if I need to. But what I would like is to create a Car object dynamically in QML, so I can pass it back to C++.

I tried:

MouseArea
{
    anchors.fill: parent
    onClicked: {
        component = Qt.createQmlObject("Car { id: car_1; carName : \"H1\"; carBrand : \"Hummer\"; carPrice : 125000; }",
                                       parent, "dynamicSnippet1");

        myCarModel.appendRowFromQml(component);
    }
}

but no luck. With the static approach, works fine:

MouseArea
{
    anchors.fill: parent
    onClicked: {
        myCarModel.appendRowFromQml(car_1);
    }
}

Is there a way to dynamically create a C++ object from the QML side? I also couldn't use Qt.createComponent because there is no *.qml file in which Car is defined, as Car was defined in C++.

Upvotes: 7

Views: 5355

Answers (3)

cavitsinadogru
cavitsinadogru

Reputation: 1030

Actually all qml objects are dynamically allocated. In your case Car has also. Loader and other alternatives are just for directing it over qml. So if you like to pass a qml object on C++ side, the only thing you need to have a slot/invokable function with Car * parameter. In your slot/invokable function, you must specify that you are taking the objects ownership to qml engine.

Suppose you have a Car class something similar like this,

class Car : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
    explicit Car(QObject *parent = Q_NULLPTR);
    ~Car();

    QString name();
    void setName(const QString &name);

signals:
    void nameChanged();

private:
    QString m_name;
};

And a Store class similar to this,

class Store : public QObject {
    Q_OBJECT
public:
    explicit Store(QObject *parent = Q_NULLPTR);

    Q_INVOKABLE void sell(Car *car);
};

And if you pass your Car object to Store object on qml,

Car {
    id: car1
    name: "H1"
}

MouseArea {
    anchors.fill: parent
    onClicked: Store.sell(car1);
}

then you must to specify the object ownership in your sell function,

void Store::sell(Car *car)
{
    qDebug() << car->name() << "just sold!!";
    QQmlEngine::setObjectOwnership(car, QQmlEngine::CppOwnership);
    delete car; // proof of the car is dynamically allocated
}

Upvotes: 1

Tarod
Tarod

Reputation: 7170

As I said in the comments, the problem is the variable component, which doesn't exist at that time.

So to fix the problem it is enough to replace the following code:

onClicked: {
    component = Qt.createQmlObject(...);

by:

onClicked: {
    var component = Qt.createQmlObject(...);

Upvotes: 2

user2520133
user2520133

Reputation: 59

You can use a Loader .

Something like this:

Loader {
   id: carLoader
   active: false
   sourceComponent:
   Car {
       id : car_1
       carName : "H1"
       carBrand : "Hummer"
       carPrice : 125000
   } 

MouseArea
{
    anchors.fill: parent
    onClicked: carLoader.active:true
}

Upvotes: 2

Related Questions