Reputation: 167
I have written a simple paint program and I'm having trouble with a task. I want to be able to delete/remove lines that have been drawn. When ButtonPress-1 is down is creates a line until ButtonRelease-1 is triggered (ButtonPress-1 is up). When pressing the 'Reset' button I want the line to be deleted/removed. I currently have it so when I press 'Reset' the program restarts itself, which is a bad solution.
from Tkinter import *
import tkMessageBox
import sys
import os
import subprocess
b1 = "up"
xold, yold = None, None
color= "black"
linesize = 2
def main():
global root
root = Tk()
global drawing_area
drawing_area = Canvas(root, width=1050, height=1200, background="white")
drawing_area.pack()
drawing_area.bind("<Motion>", motion)
drawing_area.bind("<ButtonPress-1>", b1down)
drawing_area.bind("<ButtonRelease-1>", b1up)
button1 = Button(root, text = "Reset", command = restart_program, anchor = N)
button1.configure(width = 3, background = "#FFFFFF", relief = FLAT)
button1_window = drawing_area.create_window(640, 0, anchor=N, window=button1)
root.geometry('1050x1200')
root.geometry('+0+720')
root.mainloop()
def restart_program():
python = sys.executable
os.execl(python, python, * sys.argv)
def b1down(event):
global b1
b1 = "down"
def b1up(event):
global b1, xold, yold
b1 = "up"
xold = None
yold = None
def motion(event):
if b1 == "down":
global xold, yold
if xold is not None and yold is not None:
event.widget.create_line(xold,yold,event.x,event.y,smooth=TRUE,fill = color, width=linesize)
xold = event.x
yold = event.y
if __name__ == "__main__":
main()
Upvotes: 0
Views: 3328
Reputation: 5933
if you want it to delete all items on the canvas you can call canvas.delete("all")
Or you can create the lines with a tag, and then delete by tag
so you could change:
event.widget.create_line(xold,yold,event.x,event.y,smooth=TRUE,fill = color, width=linesize)
to:
event.widget.create_line(xold,yold,event.x,event.y,smooth=TRUE,fill = color, width=linesize, tag="line")
and then call: canvas.delete("line")
this will delete all items with that tag.
EDIT: further to the origional request here is a code sample that allows simple undo/redo functions, note the following drawbacks:
if you undo an item and then draw a new item manually, redo will still put back the removed line
import Tkinter as tk
import tkMessageBox
import sys
import os
class App(tk.Tk):
b1 = "up"
xold, yold = None, None
color= "black"
linesize = 2
counter = 1 #keeps track of the current working line, is incremented as soon as line is finished
undone = [] #keeps a list of coordinate lists on undone items
def __init__(self):
tk.Tk.__init__(self)
self.drawing_area = tk.Canvas(self, width=600, height=600, background="white")
self.drawing_area.pack()
self.drawing_area.bind("<Motion>", self.motion)
self.drawing_area.bind("<ButtonPress-1>", self.b1down)
self.drawing_area.bind("<ButtonRelease-1>", self.b1up)
self.button1 = tk.Button(self, text = "Reset", command = self.blank_canvas, anchor = tk.N)
self.button1.configure(width = 3, background = "#FFFFFF", relief = tk.FLAT)
self.button1.pack(side="left")
self.button2 = tk.Button(self, text = "Undo", command = self.undo, anchor = tk.N)
self.button2.configure(width = 3, background = "#FFFFFF", relief = tk.FLAT)
self.button2.pack(side="left")
self.button3 = tk.Button(self, text = "Redo", command = self.redo, anchor = tk.N)
self.button3.configure(width = 3, background = "#FFFFFF", relief = tk.FLAT)
self.button3.pack(side="left")
def blank_canvas(self):
self.drawing_area.delete("line")
def undo(self):
self.counter -= 1 #decrements the counter to look at the previous item
currentlist = [] #creates a list to store the coordinates in
for item in self.drawing_area.find_withtag("line"+str(self.counter)): #find all sub lines from the previous line
currentlist.append(self.drawing_area.coords(item)) #get and add the coordinates to the working list
self.drawing_area.delete("line"+str(self.counter)) #delete all items of the current line
self.undone.append(currentlist) #add the working list to the stored list
def redo(self):
try:
currentlist = self.undone.pop() #fetch and remove last set of coordinates
for coords in currentlist: #for set of coordinates redraw subline
self.drawing_area.create_line(coords,smooth=tk.TRUE,fill = self.color, width=self.linesize, tags=["line", "line"+str(self.counter)])
self.counter += 1 #re increment counter
except IndexError:
pass #occurs if list is empty
def b1down(self, event):
self.b1 = "down"
def b1up(self, event):
self.b1 = "up"
self.xold = None
self.yold = None
self.counter += 1
def motion(self, event):
if self.b1 == "down":
if self.xold is not None and self.yold is not None:
event.widget.create_line(self.xold,self.yold,event.x,event.y,smooth=tk.TRUE,fill = self.color, width=self.linesize, tags=["line", "line"+str(self.counter)])
self.xold = event.x
self.yold = event.y
if __name__ == "__main__":
app = App()
app.mainloop()
Upvotes: 4