Search code examples
c++qtc++11qgraphicssceneqgraphicsitem

Constrain QGraphicsItem movement with mouseMoveEvent


I am attempting to properly constrain the movement of a QGraphicsItem (specifically QGraphicsRectItem) without changing the native behavior to function as a scrollbar on the X-axis.

I tried overriding the mouseMoveEvent function, but then I need to re-write the behavior for the rectangle in both the X and Y directions. At best, I can get the rectangle to snap to a single position with the mouse. (Here the rectangle will snap so the mouse holds it at the midpoint):

void SegmentItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
  setY(0);
  setX(event->scenePos().x() - boundingRect().width()/2);
}

I'm looking at itemChange right now, as described here, but it looks a little unwieldy and not exactly elegant. EDIT: This should work, but I currently cannot coerce it to work.

Is there a way to just constrain the y-axis movement? (I will also need to create endstops for the scrollbar, but later.)


Solution

  • I tinkered with the code from the itemChange Class Reference Page, and enhanced it so all four corners of my QGraphicsRectItem would stay within the QGraphicsScene:

    QVariant SegmentItem::itemChange(GraphicsItemChange change, const QVariant &value)
     {
         if (change == ItemPositionChange && scene()) {
             // value is the new position.
             QPointF newPos = value.toPointF();
             QRectF rect = scene()->sceneRect();
             rect.setWidth(rect.width() - boundingRect().width());
             rect.setHeight(0);
             if (!rect.contains(newPos)) {
                 // Keep the item inside the scene rect.
                 newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
                 newPos.setY(2);
                 return newPos;
             }
         }
         return QGraphicsItem::itemChange(change, value);
     }