How does QGraphicsItem::prepareGeometryChange() work?
Asked Answered
L

1

16

According to the Qt docs, it "Prepares the item for a geometry change. Call this function before changing the bounding rect of an item to keep QGraphicsScene's index up to date. prepareGeometryChange() will call update() if this is necessary."

What I don't understand is how QGraphicsItem knows when the bounding rect changes, and how it knows when to call update(). Are you ever supposed to call update() yourself after calling prepareGeometryChange() and then changing the bounding rectangle?

I'd greatly appreciate some insight into what appears to be a clairvoyant method.

Leora answered 23/3, 2012 at 3:1 Comment(0)
N
22
  • how QGraphicsItem knows when the bounding rect changes?

I think you know. Let's say you have a QGraphicsItemGroup aggregating several child items, and you want to show only one child at a time. The bounding rect of the group item needs to be the same as the bounding rect of the currently selected item:

QRectF MyItemGroup::boundingRect() const
{
    QRectF rect;
    if (currentItem_) {
        rect = currentItem_->boundingRect();
    }
    return rect;
}

Suppose you have a method to change which one of the children has to be shown:

void MyItemGroup::setCurrentItem(MyItem * item)
{
    if (list_of_items_.contains(item)) {
        prepareGeometryChange();
        currentItem_ = item;
    }
}

If you comment out prepareGeometryChange, the view will not ask again for MyItemGroup's bounding rect, and the update of the item (triggered somewhere else) will involve the wrong rect.

  • how it knows when to call update()?

According with the QGraphicsItem sources, inside the prepareGeometry method update is called only in two cases:

  1. if someone is connected to the changed signal
  2. if the scene has no views

more details here

  • Are you ever supposed to call update() yourself after calling prepareGeometryChange() and then changing the bounding rectangle?

I think the answer is No. Aside from the call to update, prepareGeometryChange marks as dirty the item region on the scene, causing a repaint of the region itself. In my experience this sufficed in the 100% of the cases, so I didn't need to call update().

Not answered 23/3, 2012 at 9:6 Comment(2)
more generally, you could precise it should be called whenever the input of ::boundingRect() computation changes. Your example is right though.Teshatesla
Thanks again, and sorry for the delay!Leora

© 2022 - 2024 — McMap. All rights reserved.