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        
    }       
}
5
  • what's your logic for creating these objects ? Commented Oct 23, 2018 at 16:51
  • What exactly do you mean by logic ? Commented Oct 24, 2018 at 7:02
  • how are you going to create these objects ? randomly or is there a scheme you are following ? Commented Oct 24, 2018 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. Commented Oct 25, 2018 at 7:15
  • I'm talking about the CREATION of these objects , not the INTERACTION or POST-CREATION Commented Oct 25, 2018 at 16:59

1 Answer 1

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");
Sign up to request clarification or add additional context in comments.

4 Comments

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 check the update and we are done now :) don't forget to mark the answer if it suits your needs
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 try to understand your tree of objects and children objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.