June 11, 2012 1 Comment
Cut to Art Gallery. A large sign says: ‘Italian Masters of the Renaissance’. Two art critics wandering through. They stop in front of a large Titian canvas. The canvas is about ten foot high by six foot wide.
First Critic Aren’t they marvelous? The strength and boldness… life and power in those colours.
Second Critic This must be Titian’s masterpiece.
First Critic Oh indeed – if only for the composition alone. The strength of those foreground figures … the firmness of the line…
Second Critic Yes, the confidence of the master at the height of his powers.
In this tutorial we are going to have a look at a new Tkinter widget called the Canvas. A canvas widget, is, somewhat like a real canvas, something that you can throw paint or other stuff all over. If you want to program games or animation you need to have an understanding of coordinate systems and computer animation. A basic understanding of coordinates is the main aim of this tutorial. In the process we will also incidentally cover another type of event – Exercise – find the new event. What is it called?
For this tutorial I want you to create a new file in your python4kids directory called canvassing.py
# -*- coding: utf-8 -*- from Tkinter import * class Canvassing(): def __init__(self, parent = None): self.canvas = Canvas(width=300, height=200, bg = "blue") self.canvas.pack() Canvassing() mainloop()
This code, when run, should give you something that looks like this (click the close widget to close):
The default background is a sort of white, and I thought you might not be able to tell against the WordPress site, so I used blue instead. Isn’t Python clever to know what blue is? I hope you can also tell that if you put different numbers in for width and height you’d get a different looking rectangle.
Exercise: Change the height or width parameters (but not both) and see what you get, try a couple of different values. Now try changing both the height and width parameters.
It’s important that you do the exercise as it demonstrates a relationship between the numbers and the size of the grid. In our example, we have a rectangle which is wider (300) than it is tall (200). In fact, if you were to look closely and count carefully, you would find that there are literally 300 blue dots along the bottom of the rectangle and 200 blue dots running up each side.
Exercise: Change width to be 10 and the height to be 1:
self.canvas = Canvas(width=10,height=1, bg = "blue")
now, go find a magnifying glass and count the dots in the canvas.
Each of those dots is called a pixel (short for picture element). Our original canvas was 300 pixels wide and 200 pixels high. It had a total of 60,000 (ie 300×200) individual pixels! Computers display their information by changing each of those individual pixels. Now, let’s make another tiny canvas and draw two tiny (1 pixel wide) lines on our new tiny canvas (save this to canvassing10x2.py):
# -*- coding: utf-8 -*- from Tkinter import * class Canvassing(): def __init__(self, parent = None): self.canvas = Canvas(width=10,height=2, bg = "blue") self.canvas.pack() self.canvas.create_line(1,1,2,1,fill="red") self.canvas.create_line(5,2,6,2,fill="yellow") Canvassing() mainloop()
This should give you a window that looks something like this (grab an edge and expand it to get a close widget):
With this you should just about be able to see the two pixels we coloured in (don’t do this generally by the way, Tkinter is not built for doing pixel operations). The first is the red pixel in the top left corner. The second is the yellow pixel on the bottom in the middle. In case you don’t have a magnifying glass, here’s a photo I took of my screen which shows it a little better:
The pixel boundaries are obvious in this photo (see the grid lines?). If you look hard you can count the pixels (the photo is a little too good because it shows the subpixel array* used by my monitor to create the colours). For good measure here is the original picture blown up 4x:
So, why is the red in the top left and the yellow in the bottom middle? Well, the canvas is 10 pixels wide and is 2 pixels high. So you can identify each of the pixels by whether they’re on the top row or bottom row, and how far along they are. In this case, we created a red line starting at 1,1 and ending at 2, 1. In each case the first number is how far along from the left and the second number is how far down from the top. So 1,1 is the first pixel on the first line while 2,1 is pixel two on line 1 (if you look closely we’ve actually ended up with a black pixel at pixel 2.
In the second case (5,2,6,2) we drew a line from pixel 5 on line 2 (5,2) to pixel 6 on line 2 (6,2). Since 5 is midway between 1 and 10 it looks like it’s in the middle.
So, what’s all this about? Well anything to do with manipulating a canvas is about coordinates. That is, what pixel on what line. Larger canvases just mean more pixels to play with. Here we had 20 pixels (ten pixels each line on two lines) but our original example had 60,000. A computer screen with a resolution of 1024 x 768 (which, as at June 2012, Wikipedia alleges represents about 20% of web users) has three quarters of a million pixels (786,432). The bottom line is that if you understand how coordinates work, then you’re already a good way there to doing computer graphics and animations.
In the last example we use an event to print out the coordinates of the mouse as you move it around the canvas (save this to canvassingCoordinates.py):
# -*- coding: utf-8 -*- from Tkinter import * formatString = "x: %03d, y: %03d" class Canvassing(): def __init__(self, parent = None): self.canvas = Canvas(width=100,height=100, bg = "blue") self.canvas.pack() self.readout = Label(text="This is a label") self.readout.pack() self.canvas.bind("<Motion>",self.updateCoordinates) def updateCoordinates(self,event): self.readout.config(text = formatString%(event.x, event.y)) Canvassing() mainloop()
Homework: 1. There’s something about the readout which doesn’t make sense. What is it?
2. Explain what is happening here. How does the label readout work?
* On my LCD each “pixel” is actually a group of three smaller pixels, one red, one blue, one green.