Why childrenRectChanged is not emitted, but calling childrenRect "fixes" it?

191 Views Asked by At

Goal

I need to know when and how the collective geometry of the children of Foo, a subclass of QQuickItem, changes.

Problem

I have connected a lambda to the QQuickItem::childrenRectChanged signal, but it is never emitted. Strangely enough, if I call childrenRect somewhere, the signal starts getting emitted. childrenRect is a getter method, not a setter, so I see no reason for this "fix".

Question

Why a seemingly unrelevant call "fixes" the emition of the signal and how to make this work as expected without calling childrenRect?

Reproducible example

Here is an example I have prepared to demonstrate the issue:

Foo.h

#include <QQuickItem>

class Foo : public QQuickItem
{
    Q_OBJECT
public:
    explicit Foo(QQuickItem *parent = nullptr) :
        QQuickItem(parent) {
        childrenRect(); // After commenting this childrenRectChanged is not emitted anymore
        connect(this, &Foo::childrenRectChanged, [this](){
            qDebug() << childrenRect();
        });
    }
};

The class is registered in main.cpp like this:

qmlRegisterType<Foo>("Foo", 1, 0, "Foo");

and used in main.qml in the following way:

import QtQuick 2.15
import QtQuick.Window 2.15
import Foo 1.0

Window {
    width: 300; height: 400; visible: true; color: "black"
    title: qsTr("Children Rect")

    Foo {
        anchors.centerIn: parent

        Rectangle {
            anchors.bottom: lightMid.top
            anchors.horizontalCenter: parent.horizontalCenter
            width: 50; height: width; radius: 0.5*width
            color: "red"
        }

        Rectangle {
            id: lightMid

            anchors.centerIn: parent
            width: 50; height: width; radius: 0.5*width
            color: "yellow"
        }

        Rectangle {
            anchors.top: lightMid.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            width: 50; height: width; radius: 0.5*width
            color: "green"
        }
    }
}

Edit

The documentation of QQuickItem::childrenRect says:

This property holds the collective position and size of the item's children.

This property is useful if you need to access the collective geometry of an item's children in order to correctly size the item.

Access functions:

QRectF childrenRect()

However, as @Amfasis mentioned in the comments, this method is not just a simple getter. Here is the code:

QRectF QQuickItem::childrenRect()
{
    Q_D(QQuickItem);
    if (!d->extra.isAllocated() || !d->extra->contents) {
        d->extra.value().contents = new QQuickContents(this);
        if (d->componentComplete)
            d->extra->contents->complete();
    }
    return d->extra->contents->rectF();
}
0

There are 0 best solutions below