Home > Net >  Drawing with mouse on Tkinter Canvas
Drawing with mouse on Tkinter Canvas

Time:12-19

I found the following piece of code here.

from tkinter import *

canvas_width = 500
canvas_height = 150

def paint( event ):
   python_green = "#476042"
   x1, y1 = ( event.x - 1 ), ( event.y - 1 )
   x2, y2 = ( event.x   1 ), ( event.y   1 )
   w.create_oval( x1, y1, x2, y2, fill = python_green )

master = Tk()
master.title( "Painting using Ovals" )
w = Canvas(master, 
           width=canvas_width, 
           height=canvas_height)
w.pack(expand = YES, fill = BOTH)
w.bind( "<B1-Motion>", paint )

message = Label( master, text = "Press and Drag the mouse to draw" )
message.pack( side = BOTTOM )
    
master.mainloop()

It lets you draw on a Tkinter canvas by dragging your mouse around. It works just fine when I move my mouse very very slowly but the moment I move it a bit faster, the lines end up broken. Here's what I mean:

Screenshot of the Tkinter window

The line on the top was drawn slowly. The one on the bottom, rather quickly. As you can see, the bottom one is missing points in many places. How do I fix this?

CodePudding user response:

If you want to draw a line, you need to register the coordinates of where the mouse moves and create line based on that using create_line method because it connects those points. So append positions of mouse to a list and draw a line and use the coordinates from that list. When you start drawing (click mouse), append the starting coordinates. Then on movement append the coordinates, delete the previous line (basically updating) and draw a new one. When mouse button is released clear the list of points and set the current line id to None to indicate that currently no line is drawn.

import tkinter as tk

line_id = None
line_points = []
line_options = {}


def draw_line(event):
    global line_id
    line_points.extend((event.x, event.y))
    if line_id is not None:
        canvas.delete(line_id)
    line_id = canvas.create_line(line_points, **line_options)


def set_start(event):
    line_points.extend((event.x, event.y))


def end_line(event=None):
    global line_id
    line_points.clear()
    line_id = None


root = tk.Tk()

canvas = tk.Canvas()
canvas.pack()

canvas.bind('<Button-1>', set_start)
canvas.bind('<B1-Motion>', draw_line)
canvas.bind('<ButtonRelease-1>', end_line)

root.mainloop()

Also:
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.

  • Related