1

I am trying to create a qml object dynamically in c++ using the object of c++ class. Below is the minimal code for my approach. Upon execution of this code and after clicking, the application is crashing(see the comment in main.qml).

I have pasted the code below and It can be downloaded here.

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "scene.h"
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    scene sc(engine);

    QQmlContext* context = engine.rootContext();
    context->setContextProperty("sc", &sc);

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

scene.h

#ifndef SCENE_H
#define SCENE_H

#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
class scene : public QObject
{
    Q_OBJECT
public:
    explicit scene(QQmlApplicationEngine& engine, QObject *parent = nullptr);
    QQmlApplicationEngine& engine;

public slots:
    void create_rect_object();
};

#endif // SCENE_H

scene.cpp

#include "scene.h"

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
{

}    
void scene::create_rect_object()
{
    QQmlComponent component(&engine, QUrl::fromLocalFile("myrect.qml"));
    QObject *object = component.create();
    object->setProperty("width", 200);
    object->setProperty("height", 150);
    object->setProperty("color", "blue");
}

main.qml

import QtQuick 2.11
import QtQuick.Window 2.11

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    Rectangle{
        anchors.fill: parent
        color: "red"
        MouseArea{
            anchors.fill: parent
            onClicked: {
                console.log("Before click");
                sc.create_rect_object(); // application is crashing here
                console.log("after click");
            }
        }
    }
}

myrect.qml

import QtQuick 2.0

Rectangle {
    id:id_rec
    width: 100
    height: 100
    color: "green"
    x:0
    y:0
}

Update

The object to be created is not the child of the root of main window but child of one of the item inside the chain of children items of root of mainwindow. The pseudo structure looks like below.

main.qml

Window {       

    customitem1{
        id:id_ci1

    }    
    customitem2{
        id:id_ci1        
    }       
}

customitem1.qml

Item {       

    customitem3{
        id:id_ci3

    }    
    customitem3{
        id:id_ci4        
    }       
}
nayab
  • 2,332
  • 1
  • 20
  • 34
  • what's your logic for creating these objects ? – Redanium Oct 23 '18 at 16:51
  • What exactly do you mean by logic ? – nayab Oct 24 '18 at 07:02
  • how are you going to create these objects ? randomly or is there a scheme you are following ? – Redanium Oct 24 '18 at 17:24
  • These objects are drag and dropped by the user and then end positions, properties are save in database. Later when the database is reloaded, these objects should in same position with same properties. In short restoring the previous context. – nayab Oct 25 '18 at 07:15
  • I'm talking about the **CREATION** of these objects , not the **INTERACTION or POST-CREATION** – Redanium Oct 25 '18 at 16:59

1 Answers1

3

[UPDATED]

You have two errors for crashing and one for not showing rectangles

1.Your scene's Constructor member initializer list is falsy which causes the app crash

(TIP : use different naming for members of the class by prefixing them with m_ e.g: m_engine for READABILITY and not get confused)

//Correct WAY
class Something
{
 private:
    int m_value1;
    double m_value2;
    char m_value3;

 public:
    //#################  YOUR CASE  ###############################
    Something(int number) : m_value1(number), m_value2(2.2), m_value3('c') // directly initialize our member variables
    {
    // No need for assignment here
    }
    //#############################################################
    Something() : m_value1(1), m_value2(2.2), m_value3('c') // directly initialize our member variables
    {
    // No need for assignment here
    }
    void print()
    {
         std::cout << "Something(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
    }
}

and it should be like this :

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(engine),QObject(parent)

instead of

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)

2.The url of myrect.qml which you get from local file that isn't found at runtime caused the app crash aslo and the one of remedies is to load it from your qrc file

 QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));

3.And you'll notice after clicking you got no rectangles that's because the rectangles getting created doesn't have a parent and by changing your create_rect_object()(In this example the parent is the invisible root of our window contentItem) you'll get some rectangles :)

//A QQuickWindow always has a single invisible root item containing all of its content.
//To add items to this window, reparent the items to the contentItem or to an existing item in the scene.
//http://doc.qt.io/qt-5/qquickwindow.html#contentItem-prop



void scene::create_rect_object()
{
    QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));

    QObject *object = component.create();
    QQuickItem *item = qobject_cast<QQuickItem*>(object);
    // Set the parent of our created qml rect
    item->setParentItem((QQuickItem*)((QQuickWindow *) engine.rootObjects()[0])->contentItem());
    //Set some random position and color
    item->setProperty("color", QColor::fromRgb(QRandomGenerator::global()->generate()));
    item->setX(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
    item->setY(20+qFloor(QRandomGenerator::global()->generateDouble()*20));

}

Finding QML Objects from C++

For finding objects and using them as parentItem, you have to set the objectName of your qml object

Rectangle {
             ...
             objectName : "rect_1"
             ...
}

and in C++

QObject* obj = dynamic_cast<QObject*>(engine.rootObjects()[0]).findChild("rect_1");
Redanium
  • 879
  • 5
  • 18
  • thanks for the answer, it works for the mentioned code, but I have problem with setParentItem, because my object is not directly in the main window. I mean object to be created is inside the chain of children. I will update the question with more details. – nayab Oct 22 '18 at 09:31
  • @nayab check the update and we are done now :) don't forget to mark the answer if it suits your needs – Redanium Oct 25 '18 at 20:18
  • I have already tried finding the parent object but it was not found. Any how thanks for your help. I have solved it in javascript. – nayab Oct 26 '18 at 07:07
  • @nayab try to understand your tree of objects and children objects – Redanium Oct 26 '18 at 13:33