PDA

View Full Version : QGraphicsItem::ItemIgnoresTransformations and children



pmjobin
5th December 2014, 22:46
Hi,

I'm using a QGraphicsView to display a scene comprised of a tree of QGraphicsItem nodes where leaves are geometric objects (with area) and parents (without area) are represented as selectable pins. The view can be zoomed in and out. I would like the pin to keep the same size in the viewport regardless of the zoom transform but still allow the pin children (the geometric objects) to be zoomed. I tried to set the ItemIgnoresTransformations flag on the pins but unfortunately, it seems this flag is recursively set to all the pins' children so the zoom is no longer being applied to geometric objects.

Is there a way to ignore a transform on a given QGraphicsItem (for display and selection purpose) but still pass down the transform to the its children?

Thanks,
PM

anda_skoa
6th December 2014, 10:54
You can make the pin a sibling of the tree root and use a non-visible item as their shared parent.

Cheers,
-

pmjobin
6th December 2014, 19:22
Sounds good. Thanks for the suggestion. However, a detail I omitted to mention in my previous post is that my application allows the pins to be moved around and the geometric children underneath must follow suit. Consequently, if I put the pin as a child of the tree node, the transformation of the tree node needs to mirror the transformation of the pin child while the pin child itself stays centered on the tree node. What is the proper way to achieve this?

Regards,
PM

anda_skoa
7th December 2014, 11:40
You can try implementing itemChange() so that it reacts to ItemPositionChange, but instead of accepting the value returns its current position and moves the parent instead.

Cheers,
_

pmjobin
10th December 2014, 07:01
I followed your idea of re-implementing itemChanged() to intercept ItemPositionChanged events and let the pins communicate their new positions back to their parent:


QVariant PinItem::itemChange(GraphicsItemChange change, const QVariant& value) {
if (change == QGraphicsItem::ItemPositionChange) {
parentItem()->setPos(value.toPointF());
return pos();
}
return value;
}

Obviously, since the pin is centered on the parent origin and the parent is given the pin position, it is warped back to the scene origin every time a new move operation is initiated. A naive solution would be to add the new pin position to the parent position rather than replace it:


QVariant PinItem::itemChange(GraphicsItemChange change, const QVariant& value) {
if (change == QGraphicsItem::ItemPositionChange) {
parentItem()->setPos(parentItem()->pos() + value.toPointF());
return pos();
}
return value;
}

But this doesn't work as intended because the parent position is then accumulated at every step of the translation which accelerate it away from the scene origin. Any suggestion?

Thanks for your help,
PM

anda_skoa
10th December 2014, 11:04
How about calculating the difference between pos and value and adding that to parent's pos?

Cheers,
_

pmjobin
10th December 2014, 16:58
By "pos", I assume you meant the pin position relative to its parent? In my case, the pin position is always (0, 0) aka centered on its parent origin. Subtracting it from "value" would behave just like the second piece of code in my last post.

Another test I've done is to let the pin acquire "value" as its new position and do the subtraction you mentioned. Doing so, the parent follow the mouse cursor as intended but the pin moves away from its parent origin.

Thanks,
PM

pmjobin
10th December 2014, 19:53
After banging my head against the wall a few times, I finally managed to find a solution. It's slightly devious but it does in fact achieve the behavior I was initially aiming for. Rather than using the itemChange() callback to communicate ItemPositionChange, I use it to communicate ItemSelectedChange. More precisely, every time a pin is selected, I select it's parent instead. Subsequently, when a translation is initiated, the parent follows the cursor and the pin isn't moved relatively to its parent, as intended.

Thanks again for your help!
PM