撤銷,重做,任何編輯器的必備工具。還是Qt的提供的標準解決方案。
QUndoCommand;QUndoStack;QUndoView;
圖形編輯的每一個動作都應該有相應的撤銷和重做機制。我們爲每個動作派生一個對象。
Qt demo裏提供了兩個例子,一個是使用QGraphic是View圖形框架的,一個是Qt自己寫的一個簡單的圖形編輯器。
這兩個都可以參考。這裏簡單的描述一下我自己抄來的。
class MoveCommand : public QUndoCommand
{
public:
MoveCommand(QGraphicsScene *graphicsScene, const QPointF & delta ,
QUndoCommand * parent = 0);
void undo() Q_DECL_OVERRIDE;
void redo() Q_DECL_OVERRIDE;
private:
QList<QGraphicsItem *> items;
QGraphicsScene *myGraphicsScene;
QPointF myDelta;
bool bMoved;
};
MoveCommand::MoveCommand(QGraphicsScene *graphicsScene, const QPointF &delta, QUndoCommand *parent)
: QUndoCommand(parent)
{
items = graphicsScene->selectedItems();
myDelta = delta;
myGraphicsScene = graphicsScene;
bMoved = true;
}
//! [2]
void MoveCommand::undo()
{
foreach (QGraphicsItem *item, items) {
item->moveBy(-myDelta.x(),-myDelta.y());
}
myGraphicsScene->update();
setText(QObject::tr("Move %1,%2")
.arg(-myDelta.x()).arg(-myDelta.y()));
bMoved = false;
}
//! [2]
//! [3]
void MoveCommand::redo()
{
if ( !bMoved ){
foreach (QGraphicsItem *item, items) {
item->moveBy(myDelta.x(),myDelta.y());
}
myGraphicsScene->update();
}
setText(QObject::tr("Move %1,%2")
.arg(myDelta.x()).arg(myDelta.y()));
}
多個對象移動的動作是交給scene處理的,所以這裏認爲這個動作之前對象已經移動過了,在這個類里加了一個bMoved的標記, QUndoStack::push方法默認會調用redo方法,
所以第一次redo是不需要做的,除非做過undo後,再執行redo才能移動對象。
我們可以創建一個QUndoView來觀察 undoStack裏的動作列表,不過發現如果在裏面跳着執行,undostack會亂套,所以看看就好。