2

I have a QML object, which can create the same objects inside of it. The function addChildRect is called from C++. Each object is provided with its unique id and objectName (for each object they are the same). I want to get access to them from C++ using QObject::findChild, but for dynamically created object this function always returns null pointer. My suggestion is, that this function parses only objects, that were in QML initially. How can I get access to dynamically created objects from C++?

Rect.qml

Rectangle {
    color: "red"
    function addChildRect(id,x,y,width,height)
    {
        var component;
        component = Qt.createComponent("Rect.qml");
        component.createObject(this, {
                               id:id,
                               objectName:id,
                               x:x,
                               y:y,
                               width:width,
                               height:height});
    }
}

C++ code:

//find element
auto parentRectView = engine.rootObjects().first()->findChild<QObject*>(QString::number(id())); 


//create element
QMetaObject::invokeMethod(parentRectView,"addChildRect",
                          Q_ARG(QVariant,id()),
                          Q_ARG(QVariant,m_position.x()),
                          Q_ARG(QVariant,m_position.y()),
                          Q_ARG(QVariant,m_size.height()),
                          Q_ARG(QVariant,m_size.width()));
5
  • 2
    I guess you should set parent for dynamically created objects to find if with QObject::findChild. Also, to avoid unnecessary actions you just can return pointer to created object from addChildRect to C++ Commented Feb 16, 2017 at 10:20
  • @folibis thank you for your answer? did I understand you properly, that I should add parent: this in QML object construction code? Also could you please provide me simple example, how to return pointer from QML? Commented Feb 16, 2017 at 10:28
  • See my answer below Commented Feb 16, 2017 at 10:51
  • 2
    Trying to "find" objects created in QML is usually a bad idea and there are almost always better ways of achieving the actual goal. For example creating multiple objects of the same type, each having its own associated C++ data set, is most likely a case for using a Repeater on the QML side and providing the data from C++ via a custom QAbstractListModel derived class. Commented Feb 17, 2017 at 10:24
  • @KevinKrammer I was facing a similar issue. Thanks for bringing up the Repeater, which is definitely the way to go since it can just have every size and each element can look different and can be in very different place through the delegate. Greetings to Graz btw. Awesome City! (I loved Schwalbennest) Commented Apr 18, 2017 at 12:45

1 Answer 1

2

Suppose we have following QML code (main.qml):

Window {
    width: 300
    height: 400
    visible: true
    id: window

    Component {
        id: testItem
        Rectangle {
            width: 100
            height: 100
            color: "green"
            anchors.centerIn: parent
        }
    }

    function addItem(name)
    {
        var component = testItem.createObject(window.contentItem, {objectName: name});
        return component;
    }
}

Pay attention - as a parent I pass Item, in my case this is Window.contentItem - a hidden root item of Window since Window isn't Item. I'm not javascript guru but I think this you use here is a pointer to the function, not to Item.

Ok, and here is a C++ code:

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject *item = dynamic_cast<QObject *>(engine.rootObjects().at(0));
QVariant retVal;
QMetaObject::invokeMethod(item, "addItem", Qt::DirectConnection,
                           Q_RETURN_ARG(QVariant, retVal),
                           Q_ARG(QVariant, "test"));

qWarning() << retVal;

In my case the output will be something like

QVariant(QObject*, QQuickRectangle(0x2c125490, name = "test"))

You just need to cast QVariant to QQuickItem or QObject.

As for finding the dynamically created objects you are right. For example the output of the following code:

QObject *rect = qvariant_cast<QObject*>(retVal);
qWarning() << rect;
QObject *myitem = item->findChild<QObject *>("test");
qWarning() << myitem;

will be:

QQuickRectangle(0x2c270d38, name = "test") 
QObject(0x0)

findChild returns null although parent of rect is set. Maybe someone can explain this strange behavior.

Sign up to request clarification or add additional context in comments.

2 Comments

Use qobject_cast for QObject and derived, it is better in several aspects, performance including.
@folibis parent in QML is the "parentItem", as in QQuickItem::parentItem() which is not necessarily the same as the QObject parent, as in QObject::parent()

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.