How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?
-
I am having a QGraphicsView which contains some QGraphicsItem I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem(Rectangle) and its connected polylines. I have a Undo-Redo feature also.
Undo - It should cancel the effect of last command executed and show previous transformation. Redo - It will undo the previous Undo.To implement this Undo-Redo feature I have used Command pattern. I have implemented Undo-Redo feature for ZoomIn-ZoomOut.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?Below Undo-Redo code is for ZoomIn-ZoomOut feature. (It is just for reference that I want to implement Hide feature's Undo-Redo something like this. )
myCommand.c
class myCommand: public QUndoCommand { public: myCommand(); myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view); private: QGraphicsItem* mItem; QGraphicsScene* mScene; QGraphicsView* mView; double scaleFactor; void undo(); void redo(); }myCommand.cpp
myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene), mView(view),scaleFactor(scale) {} void guiCommand::undo() { mView->scale(1/_scaleFactor,1/_scaleFactor); } void myCommand::redo() { mView->scale(_scaleFactor,_scaleFactor); }myView.cpp
void myView::ZoomIn() { double scaleFactor = 1.1; view->scale(scaleFactor,scaleFactor); myCommand* command1 = new myCommand(scaleFactor,scene,view); undoStack->push(command1); }myView.h
public: QUndoStack* undoStack; -
I am having a QGraphicsView which contains some QGraphicsItem I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem(Rectangle) and its connected polylines. I have a Undo-Redo feature also.
Undo - It should cancel the effect of last command executed and show previous transformation. Redo - It will undo the previous Undo.To implement this Undo-Redo feature I have used Command pattern. I have implemented Undo-Redo feature for ZoomIn-ZoomOut.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?Below Undo-Redo code is for ZoomIn-ZoomOut feature. (It is just for reference that I want to implement Hide feature's Undo-Redo something like this. )
myCommand.c
class myCommand: public QUndoCommand { public: myCommand(); myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view); private: QGraphicsItem* mItem; QGraphicsScene* mScene; QGraphicsView* mView; double scaleFactor; void undo(); void redo(); }myCommand.cpp
myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene), mView(view),scaleFactor(scale) {} void guiCommand::undo() { mView->scale(1/_scaleFactor,1/_scaleFactor); } void myCommand::redo() { mView->scale(_scaleFactor,_scaleFactor); }myView.cpp
void myView::ZoomIn() { double scaleFactor = 1.1; view->scale(scaleFactor,scaleFactor); myCommand* command1 = new myCommand(scaleFactor,scene,view); undoStack->push(command1); }myView.h
public: QUndoStack* undoStack; -
I am having a QGraphicsView which contains some QGraphicsItem I have a feature (Hide Item) which on mouse right click, hide desired QGraphicsItem(Rectangle) and its connected polylines. I have a Undo-Redo feature also.
Undo - It should cancel the effect of last command executed and show previous transformation. Redo - It will undo the previous Undo.To implement this Undo-Redo feature I have used Command pattern. I have implemented Undo-Redo feature for ZoomIn-ZoomOut.
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?Below Undo-Redo code is for ZoomIn-ZoomOut feature. (It is just for reference that I want to implement Hide feature's Undo-Redo something like this. )
myCommand.c
class myCommand: public QUndoCommand { public: myCommand(); myCommand(double scale, QGraphicsScene* scene,QGraphicsView* view); private: QGraphicsItem* mItem; QGraphicsScene* mScene; QGraphicsView* mView; double scaleFactor; void undo(); void redo(); }myCommand.cpp
myCommand::myCommand(double scale, QGraphicsScene *scene,QGraphicsView* view): mScene(scene), mView(view),scaleFactor(scale) {} void guiCommand::undo() { mView->scale(1/_scaleFactor,1/_scaleFactor); } void myCommand::redo() { mView->scale(_scaleFactor,_scaleFactor); }myView.cpp
void myView::ZoomIn() { double scaleFactor = 1.1; view->scale(scaleFactor,scaleFactor); myCommand* command1 = new myCommand(scaleFactor,scene,view); undoStack->push(command1); }myView.h
public: QUndoStack* undoStack;@tushu said in How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?:
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?
Just like you have done for your zoom in/out, you must push some kind of
QUndoCommand-derived object to the undo stack. It doesn't matter what that contains, so long as it gives you the information for the redo/undo.You have different kinds of actions to undo/redo --- first the zoom, now the visibility, maybe more in future. You have two approaches:
-
Stick with your current single derived class,
myCommand. Add further members for the information you will need. You presently havedouble scaleFactor;for the zoom, you would need theQGraphicsItem *and abool isVisiblefor the rectangle hide/show. Then you would also need an indicator of whether the particular instance is a zoom or visibility change. To allow for more actions, you would probably want anenum ActionType { Zoom, Visible, ... }, and aswitchstatement inundo/redo()to decide which action themyCommandrefers to. -
That may get messy over time, as you add more member variables and action types, bigger
switchstatement, etc. You may prefer to define distinct sub-classes for each action type.class ZoomUndoCommand: public QUndoCommand,class VisibiltyUndoCommand: public QUndoCommand, ... Now you create an instance and push whichever type for the action you are doing. Each one has only its own variables relevant to its action, and theundo/redo()does not need aswitchstatement. If you find there is any commonality/shared data between your classes, you can alwaysclass CommonUndoCommand: public QUndoCommand, put common code in there, and then derive your specific classes fromCommonUndoCommand.
-
-
@tushu said in How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?:
Question is : I dont know how to implement Undo-Redo for Hide feature. Means what to push into stack, what to pull ?
Just like you have done for your zoom in/out, you must push some kind of
QUndoCommand-derived object to the undo stack. It doesn't matter what that contains, so long as it gives you the information for the redo/undo.You have different kinds of actions to undo/redo --- first the zoom, now the visibility, maybe more in future. You have two approaches:
-
Stick with your current single derived class,
myCommand. Add further members for the information you will need. You presently havedouble scaleFactor;for the zoom, you would need theQGraphicsItem *and abool isVisiblefor the rectangle hide/show. Then you would also need an indicator of whether the particular instance is a zoom or visibility change. To allow for more actions, you would probably want anenum ActionType { Zoom, Visible, ... }, and aswitchstatement inundo/redo()to decide which action themyCommandrefers to. -
That may get messy over time, as you add more member variables and action types, bigger
switchstatement, etc. You may prefer to define distinct sub-classes for each action type.class ZoomUndoCommand: public QUndoCommand,class VisibiltyUndoCommand: public QUndoCommand, ... Now you create an instance and push whichever type for the action you are doing. Each one has only its own variables relevant to its action, and theundo/redo()does not need aswitchstatement. If you find there is any commonality/shared data between your classes, you can alwaysclass CommonUndoCommand: public QUndoCommand, put common code in there, and then derive your specific classes fromCommonUndoCommand.
@JonB Thank you for your reply. I tried to implement above feature. But when I Undo it is not showing back my item on the screen.
I try to explain you what I am doing.On every QGraphicsItem I have stored graph node's pointer. When I will click on any QGraphicsItem, to hide it, its paint() method gets called and in there from that QGraphicsItem, I get graph node's pointer and in graph node I have a field _isVisible. I make it false, and then I tell to paint() please hide this item.
So when I do Undo, I expect, nodes address should get, and I will make it's _isVisible = true and will tell paint() please show this item. So everything is working (I put some QDebug statements and checked ) fine but it is not getting showed on the screen. That's the problem.
In between I want to tell you, when I get nodes pointer , I iterate over all its neighbour and make their isVisible = false. So for every visited node, it's paint() gets called and there it checks isVisible = false/true. Accordingly paint() takes decision.
For undo, I call function which will iterate all its neighbour and will make isVisible = true. And paint() will see it and will show that item.
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { vPtr = this->getBoostPtr(); if(vPtr->_isVisible == false) this->hide(); else { this->show(); qDebug()<<"Undo Rect"; } }myCommand
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName); undoStack->push(command3);isRectHidden -> bool
vPtr -> nodes pointer
GraphName -> string -
-
@JonB Thank you for your reply. I tried to implement above feature. But when I Undo it is not showing back my item on the screen.
I try to explain you what I am doing.On every QGraphicsItem I have stored graph node's pointer. When I will click on any QGraphicsItem, to hide it, its paint() method gets called and in there from that QGraphicsItem, I get graph node's pointer and in graph node I have a field _isVisible. I make it false, and then I tell to paint() please hide this item.
So when I do Undo, I expect, nodes address should get, and I will make it's _isVisible = true and will tell paint() please show this item. So everything is working (I put some QDebug statements and checked ) fine but it is not getting showed on the screen. That's the problem.
In between I want to tell you, when I get nodes pointer , I iterate over all its neighbour and make their isVisible = false. So for every visited node, it's paint() gets called and there it checks isVisible = false/true. Accordingly paint() takes decision.
For undo, I call function which will iterate all its neighbour and will make isVisible = true. And paint() will see it and will show that item.
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { vPtr = this->getBoostPtr(); if(vPtr->_isVisible == false) this->hide(); else { this->show(); qDebug()<<"Undo Rect"; } }myCommand
myCommand* command3 = new myCommand(isRectHiddden,vPtr,GraphName); undoStack->push(command3);isRectHidden -> bool
vPtr -> nodes pointer
GraphName -> string@tushu
You should not have anything inpaint(). Do yourhide()/show()in theundo/redo(), just like you did for the scaling.Whatever you need to do with boost do it there.
When I will click on any QGraphicsItem, to hide it, its paint() method gets called and in there from that QGraphicsItem, I get graph node's pointer and in graph node I have a field _isVisible. I make it false, and then I tell to paint() please hide this item.
Like I said, nothing in
paint().paint()is only for drawing an item, if you need your own drawing (you don't), not for logic/changing state of gfx items. Do whatever work, boost or otherwise, on the item's click event.