Click here to Skip to main content
15,906,645 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
So drawing on a picture box does not make the drawings disappear when the application window is minimized. I have implemented an Undo functionality for my drawing application where I have a stack that adds a new bitmap when a new drawing is made on the picture box. It works as each drawing step is undone by replacing the current bitmap displayed in the picture box with the previous bitmap held in the stack. I have no idea how to implement the Redo functionality, I had an idea to add the bitmaps that are being removed from the undo stack to a new redo stack and then peek when the user presses Ctrl + Y, the problem is that it only does that once and then it stops redoing. Check my code below for more details.

What I have tried:

C#
class MyForm{
    //stack object for holding the redo bitmap states
     private Stack<Bitmap> redoStates = new Stack<Bitmap>();
    //stack object for holding the undo bitmap states
    private Stack<Bitmap> paintStates = new Stack<Bitmap>();
    //ctor
    public MyForm(){
        //this form will receive keyboard events before any other control does
        KeyPreview = true;
        //override on key down event to listen for undo, redo, paste and copy events
        KeyDown += OnKeyDown;
    }
     private void OnKeyDown(object? sender, KeyEventArgs e)
    {

     //check if the user is trying to undo
      if (e.Control && e.KeyCode == Keys.Z)
        {
            //the user is trying to undo the last paint action
            if (paintStates.Count > 0)
            {
                //add this bitmap to the redo stack before removing it
                redoStates.Push(paintStates.Peek());
                //remove the last added bitmap
                paintStates.Pop();
                drawingPanel.Image = paintStates.Peek();
            }
        }
      //check if the user is trying to redo
       if(e.Control && e.KeyCode == Keys.Y)
        {
            //the user is trying to redo the paint events
            //get the object pushed out and display it
            if (redoStates.Count > 1)
            {
                //reverse the redo states
                drawingPanel.Image = redoStates.Peek();
            }
        }
    }
}
Posted
Updated 3-Apr-23 21:13pm

1 solution

Tim, don't use bitmaps as a "undo"/"redo" method: it's really, really inefficient in memory terms as you are storing potentially huge amounts of unchanging data!

Store the actions you take to move from one picture to the next: add those to a queue as you change things - by all means perform them on a bitmap for speed - but when the user uses undo, clear the bitmap and repeat all action up to that point.

Redo isn't difficult: when you undo just take the last action off the stack, and push it onto a second stack. Then redo is just a pop from the redo stack, and a push back onto the undo stack followed by a rebuild of your picture.
When the user adds a new action to the undo stack, clear the redo stack.
 
Share this answer
 
Comments
Tim the Gamer 4-Apr-23 3:58am    
I define a data structure that will hold the drawing commands and then when the user performs a draw action such as drawing a line we add that command to the structure up to the point where he starts undoing, this makes sense. I will use this for better memory managdment as I also fear that the bitmap might make the program memeroy inefficient.
OriginalGriff 4-Apr-23 4:53am    
Don't define a data structure that holds commands, define a data structure that is the command - then create a Stack<DrawCommand> of those to hold the "undo" list.

When you redraw the whole bitmap, use the Stack.ToArray Method[^] to get the commands in a "for-able" order (it returns them in pop order, so the latest action is at index 0)
Tim the Gamer 4-Apr-23 4:58am    
Okay thanks let me implement that into the program.
Tim the Gamer 4-Apr-23 7:08am    
This is clearing all the drawn steps at once without redrawing the items till the end of the stack
Tim the Gamer 4-Apr-23 7:15am    
I created a DrawItem class with a constructor that accepts the item shape and list points of that item. Created a new Stack of the DrawItem objects and then pushed the shape type and the points whenever I draw a shape then in the undo I popped out the recently added command and looped through the remaining items to draw the items up to the current state of the stack but it removes all of them at once despite calling invalidate only once.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900