Snappy items!
by eric.agan on Dec.09, 2009, under eiCAD
Ok, so you can’t really tell from the picture, but the items now snap to the grid when moved around (if you enable that feature). Accomplishing that was a lot less trivial than I had hoped.
In short, the way Qt handles moving a QGraphicsItem around is by directing mouseMoveEvent()s to it. The default implementation grabs a list of the initial positions of all selected items in the scene (each movement of the mouse generates a call to this event handler, so this list is kept until the mouse button is released), checks for any necessary transforms, then simply adds the distance the mouse moved to the items’ position(s) and calls setPos() on them to apply the new position.
Unfortunately for me, QGraphicsItem::setPos() is not a virtual function, and since my shape primitive class is inheriting QGraphicsItem, that means when the default mouseMoveEvent() calls setPos() there’s no way for me to intercept it and replace the point with a “snapped” point. Several bottles of Bawls later, I had reimplemented mouseMoveEvent(). My implementation is very similar to the default one with the exception that, if enabled, it will snap the parts to the grid. The snapping is done by the following equation:
qRound(x / gridX) * gridX
Where x is either the x or y coordinate, gridX is the x or y spacing of the grid, and qRound() is a rounding function that returns the nearest integer (round up for ≥0.5, down for <0.5).
