6

I have a QGraphicsEllipseItem that I want to be movable and triggering signals on moving. So I subclassed QGraphicsEllipseItem and QObject and overrode the itemChange method to trigger a signal. That all seems to work but the positions that are reported seem to be relative to the old position of the item. Even if asking the item for its position seems only to retrieve the relative coordinates.

Here is some code to make clear what I have done:

class MyGraphicsEllipseItem: public QObject, public QGraphicsEllipseItem
{
  Q_OBJECT

public:

  MyGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h, QGraphicsItem *parent = 0, QGraphicsScene *scene = 0)
    :QGraphicsEllipseItem(x,y,w,h, parent, scene)
  {}

  QVariant itemChange(GraphicsItemChange change, const QVariant &value);

signals:
  void itemMoved(QPointF p);
};

QVariant MyGraphicsEllipseItem::itemChange( GraphicsItemChange change, const QVariant  &value )
{ 
  // value seems to contain position relative start of moving
  if (change == ItemPositionChange){
    emit itemMoved(value.toPointF());
  }
  return QGraphicsEllipseItem::itemChange(change, value); // i allso tried to call this before the emiting
}

this is the item creation:

  MyGraphicsEllipseItem* ellipse = new MyGraphicsEllipseItem(someX, someY, someW, someH);
  ellipse->setFlag(QGraphicsItem::ItemIsMovable, true);
  ellipse->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
  connect(ellipse, SIGNAL(itemMoved(QPointF)), SLOT(on_itemMoved(QPointF)));
  graphicsView->scene()->addItem(ellipse);

and the slot:

void MainWindow::on_itemMoved( QPointF p)
{
  MyGraphicsEllipseItem* el = dynamic_cast<MyGraphicsEllipseItem*>(QObject::sender());
  QPointF newPos = el->scenePos();
  scaleLbl->setText(QString("(%1, %2) - (%3, %4)").arg(newPos.x()).arg(newPos.y()).arg(p.x()).arg(p.y()));
}

The strange thing is that newpos and p are almost equal but contain coordinates relative to the beginning of the movement.

How do I get the current position of the dragged object? Is there another way to achieve the goal?

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80

2 Answers2

6

It's not a bug, it is standard behavior.

The constructor asks for a QRectF to determine the ellipse its size and its origin. Two commonly used sizes are (0,0,width,height) (origin at topleft) and (-0.5 * width, -0.5 * height, width, height) (origin at center).

With setPos, that origin is set at the desired position.

richelbilderbeek
  • 349
  • 3
  • 10
2

I found the reason: the constructor QGraphicsEllipseItem::QGraphicsEllipseItem ( qreal x, qreal y, qreal width, qreal height, QGraphicsItem * parent = 0 ) does not work as expected. after calling it with some x and y the item still reports 0,0 as its position. giving 0,0 to constructor and explicitly setting position with setPos(x,y) solves the thing.

I really wonder that was the intention for this behaviour. The documentation gives no hint for this.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
  • 1
    It's actually a documented behavior: what you pass in constructor are ellipse's geometrical coordinates, not `QGraphicsEllipseItem`'s `pos`: The *geometry of the ellipse is defined by rect*, and its pen and brush are initialized to pen and brush. Note that the item's geometry is provided in item coordinates, and *its position is initialized to (0, 0).* – kambala Mar 07 '18 at 17:18
  • 1
    The coordinates in the constructor define the offset of ellipsis. This is very handy to center the ellipsis on its own center. I agree I was surprised by this behavior as well but it's actually quite convenient – Overdrivr Mar 20 '18 at 16:27