Home > Software design >  Delete previous output tkinter
Delete previous output tkinter

Time:12-07

I made a paint app in Tkinter. I would like to know how to implement a function that deletes the previous action in every drawing. I made it work, however, it only deletes the very last draw but not the other ones.

What I'm trying to achieve is a type of Ctrl z function.

I made a code example:

from tkinter import *


class PaintApp(Tk):
    def __init__(self):
        super().__init__()

        # Variables for the paint function
        self.before = [0, 0]
        self.record_draw = []
        self.reverse_var = ''

        self.my_canvas = Canvas(self, bg='black')
        self.my_canvas.pack(fill=BOTH)


        self.button1 = Button(self, text=u"\u2190", command=self.delete_action)
        self.button1.pack()

        self.my_canvas.bind('<B1-Motion>', self.paint)  # event.type = 6
        self.my_canvas.bind('<ButtonRelease-1>', self.paint)  # event.type = 5

    def paint(self, event):
        x = event.x
        y = event.y

        self.current = [x, y]

        if not self.before == [0, 0]:
            self.line_create = self.my_canvas.create_line(
                self.before[0], self.before[1], self.current[0], self.current[1],
                fill='white', width=5)

            # Storing every line in a variable
            self.record_draw.append(self.line_create)

        self.before = self.current

        if event.type == '5':
            self.before = [0, 0]

            # Storing the drawing in another variable
            self.reverse_var = self.record_draw
            
            # Clearing the variable where the previous lines
            # were stored
            self.record_draw = []

    def delete_action(self):
        # Deleting the drawing
        self.my_canvas.delete(*self.reverse_var)


if __name__ == '__main__':
    a = PaintApp()
    a.mainloop()

Here's an example of two drawings, if I press the button, it'll erase the last action properly, if I press it again it won't erase the other one:

Two drawings

After button is pressed

I know it doesn't erase a second time due to my approach, I would like to know a better one to achieve what I a want.

CodePudding user response:

As you said, self.reverse_var stores only the last drawing. You need to store all the drawings instead using list:

class PaintApp(Tk):
    def __init__(self):
        ...
        self.reverse_var = []
        ...

    def delete_action(self):
        if len(self.reverse_var) > 0:
            # extract the last drawing from self.reverse_var
            # and delete the drawing
            self.my_canvas.delete(*self.reverse_var.pop())

CodePudding user response:

It can only remove the most recent action because that is the only one you are storing. What you can do is create a list and use it as a "undo-buffer", that keeps track of the users history and when the undo button is clicked it pops off the most recent action and undoes it, while leaving the remaining previous actions intact.

for example:

class PaintApp(Tk):
    def __init__(self):
        super().__init__()
        # Variables for the paint function
        self.before = [0, 0]
        self.record_draw = []
        self.reverse_var = ''
        self.undo_buffer = []    # <----- added this
        self.my_canvas = Canvas(self, bg='black')
        self.my_canvas.pack(fill=BOTH)
        self.button1 = Button(self, text=u"\u2190", command=self.delete_action)
        self.button1.pack()
        self.my_canvas.bind('<B1-Motion>', self.paint)  # event.type = 6
        self.my_canvas.bind('<ButtonRelease-1>', self.paint)  # event.type = 5

    def paint(self, event):
        x = event.x
        y = event.y
        self.current = [x, y]
        if not self.before == [0, 0]:
            self.line_create = self.my_canvas.create_line(
                self.before[0], self.before[1], self.current[0], self.current[1],
                fill='white', width=5)
            self.record_draw.append(self.line_create)
        self.before = self.current
        if event.type == '5':
            self.before = [0, 0]
            self.reverse_var = self.record_draw
            self.undo_buffer.append(self.reverse_var)  #<--- added this
            self.record_draw = []

    def delete_action(self):   # changed this
        # Deleting the drawing
        if len(self.undo_buffer):
            rev_var = self.undo_buffer.pop()
            self.my_canvas.delete(*rev_var)
  • Related