7

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++.

skypjack
  • 49,335
  • 19
  • 95
  • 187
Jacob Krieg
  • 2,834
  • 15
  • 68
  • 140
  • I'm not sure, but maybe the problem is you need to include `import QtQuick 2.0;` in the string passed to `Qt.createQmlObject` – Tarod May 16 '16 at 12:26
  • @Tarod Thanks for the answer. I also tried `component = Qt.createQmlObject("import QtQuick 2.4; import org.qtproject.models 1.0; Car { id: car_1; carName : \"H1\"; carBrand : \"Hummer\"; carPrice : 125000; }", parent, "dynamicSnippet1");` and I get `qrc:/main.qml:58: Error: Invalid write to global property "component"` when the code gets executed... – Jacob Krieg May 16 '16 at 12:31
  • 3
    Do you get the same issue if you write `var component = Qt.createQmlObject` instead of `component = Qt.createQmlObject`? – Tarod May 16 '16 at 12:36
  • @Tarod That was the problem. Crap...write an answer so I can accept it :) Thanks a lot!!! – Jacob Krieg May 16 '16 at 12:38
  • 1
    Well, thanks to you! Happy coding :) – Tarod May 16 '16 at 13:44

3 Answers3

3

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
}
2

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(...);
Tarod
  • 6,732
  • 5
  • 44
  • 50
1

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
}
cavitsinadogru
  • 940
  • 2
  • 10
  • 17