-1

I am implementing undo/redo for move operation on QGraphicsItemGroup in my graphics scene. It works decently for point entity.

My command for move looks like:

class CommandMove : public QUndoCommand
{
public:
  CommandMove(QGraphicsItemGroup *group, qreal fromX, qreal fromY,
                 qreal toX, qreal toY)
  {
      itemGroup = group;
      mFrom = QPointF(fromX, fromY);
      mTo = QPointF(toX, toY);
      setText(QString("Point move (%1,%2) -> (%3,%4)").arg(fromX).arg(fromY)
              .arg(toX).arg(toY));
  }

  virtual void undo()
  {
      itemGroup->setPos(mFrom);
  }

  virtual void redo()
  {
      itemGroup->setPos(mTo);
  }

private:
  QGraphicsItemGroup *itemGroup;
  QPointF mFrom;
  QPointF mTo;
};

My command is pushed to the undo stack as:

if (item.first->scenePos() != item.second)
    {
        mUndoStack->push(new CommandMove(item.first, item.second.x(),
                                            item.second.y(), item.first->x(),
                                            item.first->y()));
    }

item is a QPair defined as:

typedef QPair<QGraphicsItemGroup *, QPointF> item;

Implemenatation for entities like line, circle etc. requires more information as compared to point. eg., start and end points for line. How do I define my command for moving my entities?

Edit

This is my implementation for line:

if (m1)
  {
     start_p = event->scenePos();
     m1 = false;
     m2 = true;
  }
else if (!m1 && m2)
  {
     end_p = event->scenePos();
     m3 = true;
     m2 = false;
  }
if (m3)
  {
     lineItem = new Line(start_p, end_p);
  }

Here event is mousePressEvent.

Where do I use setPos to set the position of line?

Kamalpreet Grewal
  • 822
  • 1
  • 13
  • 28
  • No, you don't need more info. Setting the position of an item translates its origin to the new one. (The whole item is translated) – mhcuervo Oct 15 '14 at 14:29
  • I have did this for point. I want to do implementation for line. Would providing one end point of line suffice? – Kamalpreet Grewal Oct 15 '14 at 14:32
  • Let the `mFrom` point be the item's `pos()`, then set the position to `mTo`. That would be an implementation for graphic items. – mhcuervo Oct 15 '14 at 14:38

1 Answers1

2

I think you shouldn't care about all item's peculiarities. You can implement a move command that works well for any item or group of items. This is a modified version of your code.

class CommandMove : public QUndoCommand
{
public:
  CommandMove(QGraphicsItem *item, qreal toX, qreal toY)
  {
      mItem = item;
      mFrom = mItem->pos();
      mTo = QPointF(toX, toY);
      setText(QString("Point move (%1,%2) -> (%3,%4)").arg(mFrom.x()).arg(mFrom.y())
              .arg(mTo.x()).arg(mTo,y()));
  }

  virtual void undo()
  {
      mItem->setPos(mFrom);
  }

  virtual void redo()
  {
      mItem->setPos(mTo);
  }

private:
  QGraphicsItem* mItem;
  QPointF mFrom;
  QPointF mTo;
};

I hope this helps.

mhcuervo
  • 2,610
  • 22
  • 33
  • So you mean if I pass on the coordinates of start point of line, the end point's coordinates will be updated automatically? – Kamalpreet Grewal Oct 16 '14 at 06:06
  • Not exactly. I mean that if you pass on the position (as obtained with `pos`) of the line (not necessarily have to be the start point of the line) then the start and end point will be updated automatically. This will happen with any kind of item. – mhcuervo Oct 16 '14 at 06:59
  • Undo redo will work I know but I want to save the updated coordinates after the line is moved in a file. This would not be accomplished correctly using `pos()`. – Kamalpreet Grewal Oct 16 '14 at 08:13
  • Undo/redo mechanism is designed for undo/redo. The updated coordinates of a QGraphicsLineItem can be obtained with `line()` as well as the non updated ones. – mhcuervo Oct 16 '14 at 13:34
  • Okay I got it. The logic would be same for all entities. But how do I `setPos` for line? @mhcuervo I have edited my question. – Kamalpreet Grewal Oct 18 '14 at 01:41