PDA

View Full Version : Snap-to grid on QGraphicsItem



hardgeus
25th April 2008, 21:52
I have a QGraphicsItem implemented to represent points on a grid. My grid can be of variable resolution, and I would like the ability to enforce snap-to behavior on my points when they're drug around the graphics view. From what I can tell, there is no built-in behavior for this and I will have to impelement my own mouseMoveEvent.

My initial thought was to somehow "fudge" the QGraphicsSceneMouseEvent before I sent it up to the QGraphicsItem handler, but it seems that I don't have any access methods to set the internal values.

I checked the mouseMoveEvent code for the QGraphicsItem class, and I really don't want to have to duplicate all of the internal code. Is there any simple solution for offsetting the movements to a grid (i.e. only allow movement in 5 pixel increments etc.), or will I definitely have to re-implement the entirety of the mouseMoveEvent?

Shadowfiend
25th April 2008, 23:22
How much work does the mouseMoveEvent do in terms of actual movement? You could override the event handler, grab the position beforehand, invoke the parent's handler, and then toy with the position after that has run to snap it to your notion of a grid.

aamer4yu
25th April 2008, 23:23
You need to override the mouseMoveEvent of the item, and set the position according to the distance.

Say in mousepress event u save - m_pos = event->pos();
then in mouseMoveEvent u cud check
if( (event->pos() - m_pos) > 5 pixels)
setPos(); // set the item position.


Also you can have a look at Drag events to have a finer control of how the items move :)

hardgeus
26th April 2008, 00:01
Well, the parent handler has a pretty good chunk of code which handles the movement of all items that are currently selected in the view. So, if you have 20 points selected, moving one of them will move all of them by the same x,y offset.

This is handled in a fairly dense loop. It's not beyond my ability to duplicate and modify this code in my handler, but I really dislike implementing that much code which is dependent on the internals of the API. I would much rather find a solution that allows me to perform some minimal calculations in my hander, and somehow "fool" the parent. If my hander is too complex and dependent on the internals of the GraphicsView/Item, I can easily see it breaking with new versions of QT.

Shadowfiend
26th April 2008, 00:09
Hmm... Well, could you use the canvas's selected item list, wrap it in a group, and then manage the movement at the level of the group? This way, when the items move, all you have to check is the top-level group and adjust its position and it will filter down, right?

hardgeus
26th April 2008, 00:14
Hmm... Well, could you use the canvas's selected item list, wrap it in a group, and then manage the movement at the level of the group? This way, when the items move, all you have to check is the top-level group and adjust its position and it will filter down, right?

That sounds like a possible option...Will there be a lot of overhead caused by creating a destroying a group inside of a mouse event?

spud
26th April 2008, 00:41
Instead of reimplementing QGraphicsSceneMouseEvent, implement QGraphicsItem::itemChange(). There is an example in the documentation.

Shadowfiend
26th April 2008, 00:48
There we go. I was going to suggest overriding setPos, but then saw that it wasn't virtual.

To clarify about my suggestion, however, I wasn't suggesting that you create the group inside the mouse event, but rather when the selection changes.

wysota
26th April 2008, 07:21
I second what spud says - reimplement itemChange and make sure that when item coordinates are changed, they get snapped to the grid you want. By the way, I wouldn't represent the grid as a QGraphicsItem. Instead I would draw it inside reimplementation of drawBackground().

hardgeus
28th April 2008, 17:22
Thanks guys. I am getting the behavior I need by implementing itemChange