Apply a transformation to all QGraphicsItem in a QGraphicsScene
-
Hello, I'm trying to apply the same transformation matrix to all my QGraphicsItem in my QGraphicsScene. I would like for them to behave as a single item for this certain transformation.
My first thought was to iterate all items and apply the transformation individually, like so:
// func inside a QGraphicsScene or QGraphicsView QTransform translateMat; translateMat.translate(dx, dy); foreach (auto *item, items()) item->setTransform(translateMat, true);
This works fine when translating the items.
But for a rotation transform, each item is rotated around its own transformationOriginPoint. My goal is for them to be rotated around the same point (e.g. around the scene's QPointF(0, 0)).
So I tried working with a QGraphicsItemGroup.
// func inside a QGraphicsView QTransform translateMat; translateMat.translate(dx, dy); QGraphicsItemGroup *allItems = scene()->createItemGroup(scene()->items()); allItems->setTransform(translateMat, true); scene()->destroyItemGroup(allItems);
This worked as intended both with a translation and a rotation transform. However when my scene has many items, the delay on
scene()->destroyItemGroup(allItems);
is huge.
So is there something like a root item in a QGraphicsScene that works as a parent to all scene items? So that I can apply the transformation matrix to all of the items?
Or should I create a custom MyGraphicsScene class that has a QGraphicsItemGroup as a member and override addItem(), removeItem() and similar functions? To add every item in my group of all items, remove them etc...
Btw, I want to transform the items themselves. Applying a transformation to the view, does not help me.
-
@Asperamanca
I've tried this idea with a QGraphicsItemGroup.I created a custom class derived from QGraphicsScene with a QGraphicsItemGroup as a member. Then re-implemented addItem() and removeItem() to capture the item and add it to the group as well. The behavior of the transformations is as I wanted. However, I'm not sure if this is a good practice or not.
I tried a different solution as well. It works for the rotation that I wanted, however I iterate over all items(). So I am questioning the performance. Here it is:
QPointF rotationOrigin = mapFromScene(QPointF(0,0)); foreach (auto *item, items()) { QPointF itemRotationPoint = item->mapFromScene(rotationOrigin); QTransform rotMat; rotMat.translate(itemRotationPoint.x(), itemRotationPoint.y()); rotMat.rotate(angle); rotMat.translate(-itemRotationPoint.x(), -itemRotationPoint.y()); item->setTransform(rotMat, true); }
Both solutions work for me. However, I'm not sure if I'm missing something so I'll leave it unsolved for now.
I'll be happy If anyone has done something similar and can share their thoughts.
-
@ThThoma
The question is whether a group adds any value for your use case. And the fact addItem() and removeItem() are not virtual functions indicates you should not reimplement them.Normally, you are informed about added/removed children in QGraphicsItem::itemChange with enums
QGraphicsItem::ItemChildAddedChange and QGraphicsItem::ItemChildRemovedChangeBut in general, you shouldn't even need this if you apply the transformation on the parent item. The added child will use the parent's transformation automatically.
-
At the end I've researched again the view's transformations and concluded to support both features and warn for the complexity.
I did not re-implement the add/remove items of the scene together with a group. Thanks for the hint @Asperamanca .