Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?
Forum Updated to NodeBB v4.3 + New Features

How to implement undo-redo functionality in hiding QGraphicsItem using Command-Pattern in Qt?

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 431 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tushu
    wrote on last edited by tushu
    #1

    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;
    
    T JonBJ 2 Replies Last reply
    0
    • T tushu

      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;
      
      T Offline
      T Offline
      tushu
      wrote on last edited by
      #2

      @JonB @SGaist Could you help me in this ?

      1 Reply Last reply
      0
      • T tushu

        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;
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #3

        @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 have double scaleFactor; for the zoom, you would need the QGraphicsItem * and a bool isVisible for 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 an enum ActionType { Zoom, Visible, ... }, and a switch statement in undo/redo() to decide which action the myCommand refers to.

        • That may get messy over time, as you add more member variables and action types, bigger switch statement, 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 the undo/redo() does not need a switch statement. If you find there is any commonality/shared data between your classes, you can always class CommonUndoCommand: public QUndoCommand, put common code in there, and then derive your specific classes from CommonUndoCommand.

        T 1 Reply Last reply
        1
        • JonBJ JonB

          @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 have double scaleFactor; for the zoom, you would need the QGraphicsItem * and a bool isVisible for 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 an enum ActionType { Zoom, Visible, ... }, and a switch statement in undo/redo() to decide which action the myCommand refers to.

          • That may get messy over time, as you add more member variables and action types, bigger switch statement, 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 the undo/redo() does not need a switch statement. If you find there is any commonality/shared data between your classes, you can always class CommonUndoCommand: public QUndoCommand, put common code in there, and then derive your specific classes from CommonUndoCommand.

          T Offline
          T Offline
          tushu
          wrote on last edited by
          #4

          @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

          JonBJ 1 Reply Last reply
          0
          • T tushu

            @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

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #5

            @tushu
            You should not have anything in paint(). Do your hide()/show() in the undo/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.

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved