29. Drawing on a canvas

[status: content-mostly-written]

Prerequisites

  • The 10-hour “serious programming” course.

  • A GNU/Linux system with python3 and python3-tk installed (on an Ubuntu 16.04 system this can be done with sudo apt install python3-tk)

29.1. Simplest canvas

Drawing is usually done with the help of a graphical toolkit library. This library usually supports widgets and allows them to be arranged in a window on the scren. The widget for drawing is called a canvas and in Listing 29.1.1 is a simple example using Python’s tkinter widget set.

Listing 29.1.1 Program which draws two circles and a line.
#! /usr/bin/env python3

"""simple canvas with two discs and a line between them
"""

## we use the tkinter widget set; this seems to come automatically
## with python3 on ubuntu 16.04, but on some systems one might need to
## install a package with a name like python3-tk
from tkinter import *

canvas_width = 640
canvas_height = 480

def main():
    ## prepare a basic canvas
    root = Tk()
    w = Canvas(root, 
               width=canvas_width,
               height=canvas_height)
    w.pack()       # boiler-plate: we always call pack() on tk windows
    w.create_oval(210, 230, 230, 250, fill="yellow")
    w.create_oval(410, 230, 430, 250, fill="blue")
    w.create_line(220, 240, 420, 240)
    mainloop()

main()

Things to notice about this program:

  • It uses the library tkinter which provides calls to create a window and draw things in it.

  • The calls root = Tk() and w.pack() and mainloop are boiler-plate: almost all programs that use the tkinter toolkit will use them.

  • w = Canvas(...) creates a canvas with the given width and height. w.pack() places that canvas into the window we are using.

  • After the drawing calls create_oval() and create_line() we call mainloop(). This enters an event loop in which the widget set is waiting for events, such as the click of a button. We have not created any buttons, so mainloop() will just hang until we interrupt the progrma.

29.2. Simplest animation

Animation can be done simply by drawing onto a canvas, then changing the drawing after a small amount of time and refreshing the canvas.

In listing Listing 29.2.1

Listing 29.2.1 Program which animates a circle whose radius is growing and shrinking.
#! /usr/bin/env python3

"""simple animation of a growing/contracting disc
"""

import time
import math

## we use the tkinter widget set; this seems to come automatically
## with python3 on ubuntu 16.04, but on some systems one might need to
## install a package with a name like python3-tk
from tkinter import *

canvas_width = 640
canvas_height = 480

def main():
    ## prepare a basic canvas
    root = Tk()
    w = Canvas(root, 
               width=canvas_width,
               height=canvas_height)
    w.pack()       # boiler-plate: we always call pack() on tk windows
    for i in range(24*180):     # 3 minutes if it's 24 frames/sec
        radius = 140 + 50*math.sin(i/24.0) # oscillating radius
        center = (canvas_width/2, canvas_height/2)
        color = 'blue'
        ## clear the canvas and then draw a new disc
        w.delete('all')
        w.create_oval(center[0]-radius, center[1]-radius,
                      center[0]+radius, center[1]+radius,
                      fill=color)
        ## update the canvas
        w.update()
        time.sleep(1.0/24.0)    # 24 frames per second
    mainloop()

main()

Note that this kind of animation is not ideal: it works well, but it does not allow the program to respond to any user input or other events. For us this is OK because we are purely showing the animation, and we are not setting up any buttons or other parts to the program, but the tkinter library offers a more appropriate approach to doing animations with a method called after() which allows you to call your drawing routines and handle user interface events at the same time.

29.2.1. Exercises

Exercise 29.1

Modify the tirial animation program in Listing 29.2.1 to write the current at the bottom of the canvas. A web search for “tkinter write string on canvas” might help.

Exercise 29.2

Study how colors can be represented as combinations of red, green and blue (RGB) values. Read the introductory part of the Wikipedia article on the subject at https://en.wikipedia.org/wiki/RGB_color_model and then use the program gpick to examine how the various screen pixel colors can be represented as red, green and blue. Explore the program in detail, looking at how you can specify the RGB values and see what the result is, but you can also pick them from a color wheel, and you also use the screen picker FIXME…

Exercise 29.3

Modify the trivial animation program in Listing 29.2.1 to cycle through the colors as well as the radius. Aim for a psychadelic effect. Note that the fill= field in create_oval() can be a descriptive color name (like the "blue" that we used) but it can also specify the RGB (red, green, blue) values that form the color. A web search for “tkinter colors” might help.