Canvas

The Canvas widget can be used to draw lines, shapes, and text to create complex drawings and graphs. The origin (0, 0) of the canvas is in the top left corner. It has the keyword options:

  • background = background color
  • borderwidth
  • height
  • width

Draw lines and rectangles

To draw lines and rectangles, use these create methods:

  • create_line()
  • create_rectangle()
../_images/canvas1.png
from tklib import *
app = App('Canvas with lines and rectangles')

c = Canvas(width=600, height=300, background='lightblue')
c.create_line(10, 10, 200, 200, fill='red')
c.create_line(20, 10, 210, 200, fill='blue', width=3)
c.create_rectangle(100, 200, 150, 250, fill='green', width=2)
c.create_rectangle(300, 100, 580, 250, fill='yellow', width=5)

app.run()

canvas1.py

Create text

Text can be added to a canvas with this function:

  • create_text()
../_images/canvas2.png
from tklib import *
app = App('Canvas with ovals and text')

c = Canvas(width=600, height=300, background='lightblue')
c.create_line(10, 10, 200, 200, fill='red')
c.create_line(20, 10, 210, 200, fill='blue', width=3)
c.create_oval(100, 200, 150, 250, fill='green', width=2)
c.create_oval(300, 100, 580, 250, fill='yellow', width=5)
c.create_text(300, 150, text="Python", font='Arial 48')
c.create_text(300, 250, text="Canvas", font='Zapfino 72')

app.run()

canvas2.py

Paint with ovals

Small ovals can be used to paint with the mouse, by binding a callback function to the mouse movement.

../_images/canvas3.png
"""Painting with ovals."""
from tklib import *

class Demo(App):
    def __init__(self):
        super().__init__()
        Label("Painting using ovals", font="Arial 24")
        self.c = Canvas(width=600, height=300, background='lightblue')
        self.c.bind('<B1-Motion>', self.paint)

    def paint(self, event):
        """Draw ovals on the canvas."""
        x0, y0 = event.x-1, event.y-1
        x1, y1 = event.x+1, event.y+1
        self.c.create_oval(x0, y0, x1, y1, fill='blue')

Demo().run()

canvas3.py

Polygons

We can add our own methods to the Canvas class. For example we can define a method to add a polygon.

    def polygon(self, x0, y0, r, n, **kwargs):
        points = []
        for i in range(n):
            a = 2 * math.pi * i / n
            x = x0 + math.sin(a) * r
            y = y0 + math.cos(a) * r
            points.append(x)
            points.append(y)
        self.create_polygon(points, **kwargs)
../_images/canvas4.png
from tklib import *
app = App('Draw a polygon')

c = Canvas(width=600, height=300, background='lightblue')
c.polygon(150, 150, 100, 6, fill='blue')
c.polygon(450, 150, 80, 8, fill='red', width=5)

app.run()

canvas4.py

Random circles

The following program places circles of random size at random locations.

../_images/canvas5.png
from tklib import *
app = App('Random circles')

w, h = 600, 300
c = Canvas(width=w, height=h, background='lightblue')

for i in range(50):
    x = random.randint(0, w)
    y = random.randint(0, h)
    r = random.randint(10, 100)
    c.create_oval(x, y, x+r, y+r)

app.run()

canvas5.py

Canvas configuration

../_images/canvas6.png
"""Canvas config."""
from tklib import *

class Demo(App):
    def __init__(self): 
        super().__init__()
        Label("Canvas configuration", font="Arial 24")

        Spinbox('width', 'App.c["width"]=self.var.get()', inc=50, to=1000)
        Spinbox('height', 'App.c["height"]=self.var.get()', inc=50, to=1000)
        Combobox('background', 'white;yellow;pink;light blue', 'App.c.config(background=self.var.get())')
        Combobox('highlightcolor', 'black;red;blue;green', 'App.c.config(highlightcolor=self.var.get())')
        Combobox('relief', 'flat;sunken;raised;groove', 'App.c.config(relief=self.var.get())')
        Combobox('state', 'normal;disabled;hidden', 'App.c.config(state=self.var.get())')
        Spinbox('borderwidth', 'App.c.config(borderwidth=self.var.get())')
        
        Button('Config', 'print(App.c.config())')

        App.c = Canvas()

Demo().run()

canvas6.py

Canvas configuration with tree view

../_images/canvas7.png
"""Canvas configuration with Treeview"""
from tklib import *

class Option:
    def __init__(self, widget):
        self.w = widget
        tree = Treeview(columns=(0))
        tree.column(0, width=150)
        tree.heading(0, text='Value')
        tree.grid(row=0, column=2)

        d = self.w.config()
        print(d)
        for (k, v) in d.items():
            if len(v)>2:
                tree.insert('', 'end', text=k, values=v[-1])


class Demo(App):
    def __init__(self): 
        super().__init__()
        Label("Canvas configuration", font="Arial 24")

        App.stack[-1]=Frame()
        App.c = Canvas(background='lightblue',
            borderwidth=10,
            height=250)
        d = App.c.config()

        tree = Treeview(columns=(0))
        tree.column(0, width=150)
        tree.heading(0, text='Value')
        tree.grid(row=0, column=1)

        for (k, v) in d.items():
            if len(v)>2:
                tree.insert('', 'end', text=k, values=v[-1])

        Option(App.c)

Demo().run()

canvas7.py

Draw shapes with the mouse

../_images/canvas9.png
"""Draw shapes with the mouse."""
from tklib import *

class Demo(App):
    def __init__(self): 
        super().__init__()
        Label("Drawing shapes", font="Arial 24")

        Spinbox('width', 'App.c["width"]=self.val.get()', inc=50, to=1000)
        Spinbox('height', 'App.c["height"]=self.val.get()', inc=50, to=1000)
        Separator()
        
        Combobox('fill', 'black;red;green;blue;orange;cyan', 
            'App.c.itemconfig(App.c.id, fill=self.val.get())')
        Spinbox('width', 'App.c.itemconfig(App.c.id, width=self.val.get())', from_=1, to=20)
        Button('Delete', 'App.c.delete(App.c.id)')
        Button('Delete All', 'App.c.delete("all")')
        Combobox('type', 'arc;line;rectangle;oval', 
            'App.c.itemconfig(App.c.id, fill=self.val.get())')

        Button('Config', 'print(App.c.itemconfig(1))')
        
        App.c = Canvas()
        print(vars(App.c))
        print()
        print(dir(App.c))

        App.c.create_rectangle(20, 20, 150, 100)
    
Demo().run()

canvas9.py

Draw straight lines with the mouse

In order to draw with the mouse we have to add two bindings to the canvas:

  • <Button-1> to initiate the drawing, calling the start() method
  • <B1_Motion> to update the current drawing, calling the move() method
../_images/draw1.png
# draw straight lines on a canvas
from tklib import *

class Canvas(tk.Canvas):
    """Define a canvas with line drawing"""

    def __init__(self, **kwargs):
        # super(Canvas, self).__init__(App.stack[-1], width=w, height=h, bg='light blue')
        super(Canvas, self).__init__(App.stack[-1], **kwargs)
        self.grid()
        self.bind('<Button-1>', self.start)
        self.bind('<B1-Motion>', self.move)
        self.bind('<D>', self.print_msg)
        self.bind('<Key>', self.print_msg)
        self.bind('<Return>', self.print_msg)
        

    def start(self, event=None):
        # Execute a callback function.
        self.x0 = event.x
        self.y0 = event.y
        self.id = self.create_line(self.x0, self.y0, self.x0, self.y0)
        self.itemconfig(self.id, fill=color.var.get())
        self.itemconfig(self.id, width=thickness.var.get())

    def move(self, event=None):
        self.x1 = event.x
        self.y1 = event.y
        self.coords(self.id, self.x0, self.y0, self.x1, self.y1)

    def print_msg(self, event):
        print(event)

app = App('Drawing lines on a canvas')
color = Combobox('Color', 'black;red;green;blue;yellow;cyan;magenta')
thickness = Combobox('Thickness', '1;2;5;10;20')
Canvas(width=600, height=200)

app.run()

draw1.py