[Arjen Markus] (10 October 2002) It occurred to me that the technique of producing an ''animated display'' has not been documented with so many words on the Wiki. Well, here is my view on the subject. Suppose you have a canvas which needs to redrawn after some time. This will be our animated display, as the redrawn picture will look slightly different. There are roughly two options: * Redrawing the individual pictures is fast enough, so anybody can run the script directly and watch the movie. * Redrawing them takes either too much time or we need a compact form in which to distribute the result (say as an animated GIF file). The first part requires knowledge of the [after] command, such as in [Keeping a GUI alive]. The second part requires additional tools, such as ''ImageMagick'' ([http:///www.imagemagick.org]) to complete the job. Both approaches are relatively easy (see the script below), but they are certainly easiest on UNIX/Linux, where most tools are command-line driven. The first approach is this: * In a procedure, draw the picture. * When it completes, change the "time" parameter, use the [after] command to wait a short interval and then restart the procedure. ''Note:'' the [after] command is essential here, it will make sure that the next picture is drawn at the appropriate time. In the meantime the canvas can be drawn, events can be processed etc. The second approach just adds two steps: * When the picture is finished, save the picture in a bitmap file * When the animation is complete and we have all pictures stored on disk, use some tool to create the animation file. On UNIX/Linux, the tool to save the canvas in a bitmap file that I use frequently is "xwd": exec xwd -id [winfo $canvas] -out [format "anim%04d.xwd" $count] where "canvas" holds the name of the canvas we draw in and "count" is a counter for the picture. By formatting the names of the bitmap files in four figures, anim0000.xwd, anim0001.xwd, ..., the conversion to an animated GIF file via ImageMagick's convert becomes a single instruction: In the shell, type: > convert anim*.xwd my_anim.gif (''convert'' will convert all files to GIF files - this is based on the extensions - and as there is more than one input file, it is going to be an animated GIF file.) The script below shows an animation of a bouncing ball. Nothing particularly interesting, but it illustrates the ideas. ---- # drawBall -- # Draw a red circle at a certain height above the green ground # # Arguments: # time Time parameter, used to calculate the actual height # # Result: # None # # Note: # Assume a perfectly elastic collision. The time parameter must # be reduced to the time since the last collision. # proc drawBall {time} { global accel global velo0 global cnv_height global cnv_width set period [expr {2.0*$velo0/$accel}] set time2 [expr {$time - $period * int($time/$period)}] set grass_height 20 set radius 7 set ball_height [expr {$velo0*$time2-0.5*$accel*$time2*$time2}] set pix_height [expr { $cnv_height-$grass_height - $radius - $ball_height}] set xl [expr {0.5*$cnv_width-$radius}] set xr [expr {0.5*$cnv_width+$radius}] set yb [expr {int($pix_height)-$radius}] set yt [expr {int($pix_height)+$radius}] .cnv delete all .cnv create rectangle 0 $cnv_height $cnv_width \ [expr {$cnv_height-$grass_height}] -fill green -outline green .cnv create oval $xl $yb $xr $yt -fill red -outline black } # nextPicture -- # Prepare to call the next picture, stop after some predefined # number of steps. # # Arguments: # step Step number (converted to time) # # Result: # None # proc nextPicture {step} { # Here you can insert the code to save the current picture # # exec xwd -id [winfo id .cnv] -out [format "anim%04d.xwd" $step] # # # Draw the picture # drawBall [expr {0.1*$step}] # # Set up the next picture via the [after] command # if { $step < 1000 } { incr step after 100 [list nextPicture $step] } } # main -- # Set up the canvas, start the loop # global cnv_width global cnv_height global velo0 global accel set cnv_width 400 set cnv_height 300 set velo0 70.0 ;# m/s set accel 10.0 ;# m/s2 ;# pixels become m that way :) canvas .cnv -width $cnv_width -height $cnv_height -background white pack .cnv -fill both drawBall 0 # # Wait until the dust settles - important for saving the frames # on a slow system # tkwait visibility . nextPicture 0 ---- [[ [Arts and crafts of Tcl-Tk programming] [Category Graphics] ]]