3

I am making a POS system and I want to include an option to take signatures after a purchase. I have already tried a Tkinter method with a canvas but it is much to slow and it is very boxy any suggestions?

Here is the code I'm working with now:

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 )

mainloop()

btw this code is not mine, i got it from this website

cdlane
  • 40,441
  • 5
  • 32
  • 81
Avi Baruch
  • 112
  • 2
  • 8

2 Answers2

4

Here is a simple tkinter drawing app.

from tkinter import *


b1 = "up"
xold, yold = None, None
display_width = '500'
display_height = '500'
canvas_width = '500'
canvas_height = '500'
def main():
    root = Tk()
    root.geometry((display_width+"x"+display_height))


    drawing_area = Canvas(root,width=canvas_width,height=canvas_height,bg="white")
    drawing_area.bind("<Motion>", motion)
    drawing_area.bind("<ButtonPress-1>", b1down)
    drawing_area.bind("<ButtonRelease-1>", b1up)
    drawing_area.pack(side=RIGHT)
    root.mainloop()

def b1down(event):
    global b1
    x1, y1 = ( event.x - 4 ), ( event.y - 4 )
    x2, y2 = ( event.x + 4 ), ( event.y + 4 )
    event.widget.create_oval( x1, y1, x2, y2, fill = "black" )
    b1 = "down"           # you only want to draw when the button is down
                          # because "Motion" events happen -all the time-

def b1up(event):
    global b1, xold, yold
    b1 = "up"
    xold = None           # reset the line when you let go of the button
    yold = None

def motion(event):
    if b1 == "down":
        global xold, yold
        x1, y1 = ( event.x - 4 ), ( event.y - 4 )
        x2, y2 = ( event.x + 4 ), ( event.y + 4 )
        event.widget.create_oval( x1, y1, x2, y2, fill = "black" )
        if xold is not None and yold is not None:
            python_green = "#476042"
            x1, y1 = ( event.x - 4 ), ( event.y - 4 )
            x2, y2 = ( event.x + 4 ), ( event.y + 4 )
            event.widget.create_oval( x1, y1, x2, y2, fill = "black" )
            event.widget.create_line(xold,yold,event.x,event.y,smooth=TRUE,width=9)
    # here's where you draw it. smooth. neat.
        xold = event.x
        yold = event.y

if __name__ == "__main__":
    main()
Stef van der Zon
  • 633
  • 4
  • 13
4

a clean example:

import tkinter as tk

class Signature(tk.Canvas):
    def __init__(self, *args, **kwargs):
        self.thickness = kwargs.pop('thickness', 4)
        tk.Canvas.__init__(self, *args, **kwargs)
        self._xold = None
        self._yold = None

        self.bind('<B1-Motion>', self._on_motion)

    def _on_motion(self, event):
        x1, y1 = ( event.x - self.thickness ), ( event.y - self.thickness )
        x2, y2 = ( event.x + self.thickness ), ( event.y + self.thickness )
        event.widget.create_oval( x1, y1, x2, y2, fill='black' )
        if self._xold is not None and self._yold is not None:
            self.create_oval( x1, y1, x2, y2, fill='black' )
            self.create_line(self._xold,self._yold,event.x,event.y,smooth=True,width=self.thickness*2+1)
    # here's where you draw it. smooth. neat.
        self._xold = event.x
        self._yold = event.y

if __name__ == '__main__':
    canvas_width = '500'
    canvas_height = '500'

    root = tk.Tk()
    sig = Signature(root, width=canvas_width,height=canvas_height,bg='white', thickness=1)
    sig.pack()

    root.mainloop()

note this draws an oval at the position of the event and a line to join it up with the last event, this helps smooth the line out.

James Kent
  • 5,763
  • 26
  • 50
  • note that if you actually want to save the result you'll need to make use of another graphics library as tk doesn't have that built in. previously I've used PIL or pillow for this. – James Kent Dec 10 '18 at 14:59
  • I was able to save the canvas using PIL, I didn't have to use another library – Avi Baruch Dec 10 '18 at 16:52
  • @JamesKent Is there a way to reduce the thickness of the drawing? – Miraj50 Dec 11 '18 at 07:59
  • @Miraj50 I have edited the example to include a thickness parameter, note that when drawing the lines the offset is + and - the "thickness" and when drawing the oval the size is twice the thickness plus one pixel, this is required to make it smooth. this means the thinnest it can actually be is 2 pixels. – James Kent Dec 11 '18 at 08:06
  • @AviBaruch exactly, PIL is not part of tkinter, it is another toolkit. it integrates with tkinter making things easier than they could otherwise be, but it is not built in. – James Kent Dec 11 '18 at 08:07