6 min read

Animation is about making graphic objects move smoothly around a screen. The method to create the sensation of smooth dynamic action is simple:

  1. First present a picture to the viewer’s eye.
  2. Allow the image to stay in view for about one-twentieth of a second.
  3. With a minimum of delay, present another picture where objects have been shifted by a small amount and repeat the process.

Besides the obvious applications of making animated figures move around on a screen for entertainment, animating the results of computer code gives you powerful insights into how code works at a detailed level. Animation offers an extra dimension to the programmers’ debugging arsenal. It provides you with an all encompassing, holistic view of software execution in progress that nothing else can.

Static shifting of a ball with Python

We make an image of a small colored disk and draw it in a sequence of different positions.

How to do it…

Execute the program shown and you will see a neat row of colored disks laid on top of each other going from top left to bottom right. The idea is to demonstrate the method of systematic position shifting.

# moveball_1.py
#>>>>>>>>>>>>>
from Tkinter import *
root = Tk()
root.title("shifted sequence")
cw = 250 # canvas width
ch = 130 # canvas height

chart_1 = Canvas(root, width=cw, height=ch, background=”white”)
chart_1.grid(row=0, column=0)
# The parameters determining the dimensions of the ball and its
# position.
# =====================================
posn_x = 1 # x position of box containing the ball (bottom)
posn_y = 1 # y position of box containing the ball (left edge)
shift_x = 3 # amount of x-movement each cycle of the ‘for’ loop
shift_y = 2 # amount of y-movement each cycle of the ‘for’ loop
ball_width = 12 # size of ball – width (x-dimension)
ball_height = 12 # size of ball – height (y-dimension)
color = “violet” # color of the ball

for i in range(1,50): # end the program after 50 position shifts
posn_x += shift_x
posn_y += shift_y
chart_1.create_oval(posn_x, posn_y, posn_x + ball_width,
posn_y + ball_height,
fill=color)

root.mainloop()
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

How it works…

A simple ball is drawn on a canvas in a sequence of steps, one on top of the other. For each step, the position of the ball is shifted by three pixels as specified by the size of shift_x. Similarly, a downward shift of two pixels is applied by an amount to the value of shift_y. shift_x and shift_y only specify the amount of shift, but they do not make it happen. What makes it happen are the two commands posn_x += shift_x and posn_y += shift_y. posn is the abbreviation for position.

posn_x += shift_x means “take the variable posn_x and add to it an amount shift_x.” It is the same as posn_x = posn_x + shift_x.

Another minor point to note is the use of the line continuation character, the backslash “”. We use this when we want to continue the same Python command onto a following line to make reading easier. Strictly speaking for text inside brackets “(…)” this is not needed. In this particular case you can just insert a carriage return character. However, the backslash makes it clear to anyone reading your code what your intention is.

There’s more…

The series of ball images in this recipe were drawn in a few microseconds. To create decent looking animation, we need to be able to slow the code execution down by just the right amount. We need to draw the equivalent of a movie frame onto the screen and keep it there for a measured time and then move on to the next, slightly shifted, image. This is done in the next recipe.

Time-controlled shifting of a ball

Here we introduce the time control function canvas.after(milliseconds) and the canvas.update() function that refreshes the image on the canvas. These are the cornerstones of animation in Python.

Control of when code gets executed is made possible by the time module that comes with the standard Python library.

How to do it…

Execute the program as previously. What you will see is a diagonal row of disks being laid in a line with a short delay of one fifth of a second (200 milliseconds) between updates. The result is shown in the following screenshot showing the ball shifting in regular intervals.

Python 2.6 Graphics Cookbook

# timed_moveball_1.py
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
from Tkinter import *
root = Tk()
root.title("Time delayed ball drawing")

cw = 300 # canvas width
ch = 130 # canvas height

chart_1 = Canvas(root, width=cw, height=ch, background=”white”)
chart_1.grid(row=0, column=0)

cycle_period = 200 # time between fresh positions of the ball
# (milliseconds).
# The parameters determining the dimensions of the ball and it’s
# position.
posn_x = 1 # x position of box containing the ball (bottom).
posn_y = 1 # y position of box containing the ball (left edge).
shift_x = 3 # amount of x-movement each cycle of the ‘for’ loop.
shift_y = 3 # amount of y-movement each cycle of the ‘for’ loop.
ball_width = 12 # size of ball – width (x-dimension).
ball_height = 12 # size of ball – height (y-dimension).
color = “purple” # color of the ball

for i in range(1,50): # end the program after 50 position shifts.
posn_x += shift_x
posn_y += shift_y

chart_1.create_oval(posn_x, posn_y, posn_x + ball_width,
posn_y + ball_height, fill=color)
chart_1.update() # This refreshes the drawing on the canvas.
chart_1.after(cycle_period) # This makes execution pause for 200
# milliseconds.

root.mainloop()

How it works…

This recipe is the same as the previous one except for the canvas.after(…) and the canvas.update() methods. These are two functions that come from the Python library. The first gives you some control over code execution time by allowing you to specify delays in execution. The second forces the canvas to be completely redrawn with all the objects that should be there. There are more complicated ways of refreshing only portions of the screen, but they create difficulties so they will not be dealt with here.

The canvas.after(your-chosen-milliseconds) method simply causes a timed-pause to the execution of the code. In all the preceding code, the pause is executed as fast as the computer can do it, then when the pause, invoked by the canvas.after() method is encountered, execution simply gets suspended for the specified number of milliseconds. At the end of the pause, execution continues as if nothing ever happened.

The canvas.update() method forces everything on the canvas to be redrawn immediately rather than wait for some unspecified event to cause the canvas to be refreshed.

There’s more…

The next step in effective animation is to erase the previous image of the object being animated shortly before a fresh, shifted clone is drawn on the canvas. This happens in the next example.

The robustness of Tkinter

It is also worth noting that Tkinter is robust. When you give position coordinates that are off the canvas, Python does not crash or freeze. It simply carries on drawing the object ‘off-the-page’. The Tkinter canvas can be seen as just a tiny window into an almost unlimited universe of visual space. We only see objects when they move into the view of the camera which is the Tkinter canvas.

LEAVE A REPLY

Please enter your comment!
Please enter your name here