Search code examples
pythonpython-3.xtkinterpyautogui

How do I delete trailing objects drawn in tkinter?


My goal is to allow you to make a rectangle on your screen similar to using a rectangle or selection tool in paint. I've got it to mostly work but when you make a rectangle by holding left click and moving your mouse outward and then inward while still holding the button, it leaves behind rectangles that were previously drawn.

Example image

Alternate example when I move my mouse everywhere really fast.

import tkinter as tk
import pyautogui

def draw_rect(event, canvas, pos):
    x, y = pos
    rectangle = canvas.create_rectangle(
        x, y, event.x, event.y, outline="yellow", width=3, fill="blue"
    )


def draw_canvas(event, root, pos):
    canvas = tk.Canvas(root, bg="red")
    canvas.pack(fill=tk.BOTH, expand=True)

    root.bind("<B1-Motion>", lambda event: draw_rect(event, canvas, pos))

Solution

  • Instead of continuously drawing and deleting rectangles, you should draw a single rectangle and then modify its coordinates as you drag.

    Here's a simple example:

    import tkinter as tk
    
    root = tk.Tk()
    canvas = tk.Canvas(root, bg="black", width=400, height=400)
    canvas.pack(fill="both", expand=True)
    
    def draw_drag(event):
        canvas = event.widget
        new_x = canvas.canvasx(event.x)
        new_y = canvas.canvasy(event.y)
        x0, y0, x1, y1 = canvas.coords("current_rect")
        canvas.coords("current_rect", x0, y0, new_x, new_y)
    
    def draw_stop(event):
        canvas.dtag("current_rect")
    
    def draw_start(event):
        canvas = event.widget
        x = canvas.canvasx(event.x)
        y = canvas.canvasy(event.y)
        canvas.create_rectangle(x, y, x, y, fill="red", tags=("current_rect",))
    
    
    canvas.bind("<ButtonPress-1>", draw_start)
    canvas.bind("<ButtonRelease-1>", draw_stop)
    canvas.bind("<B1-Motion>", draw_drag)
    
    root.mainloop()