A minimal doodler explained

Richard Suchenwirth 2003-08-14 - More literate programming, hopefully useful to teach programming to children. Here is a tiny but complete script that allows doodling (drawing with the mouse) on a canvas widget:

WikiDbImage doodler.jpg

 proc doodle {w {color black}} {
    bind $w <1>         [list doodle'start %W %x %y $color]
    bind $w <B1-Motion> {doodle'move %W %x %y}
 }
 proc doodle'start {w x y color} {
        set ::_id [$w create line $x $y $x $y -fill $color]
 }
 proc doodle'move {w x y} {
        $w coords $::_id [concat [$w coords $::_id] $x $y]
 }
 pack [canvas .c -bg white] -fill both -expand 1
 doodle       .c
 bind .c <Double-3> {%W delete all}

And here it comes again, but this time with explanations (sorry, Wiki-reaper).


The "Application Program Interface" (API) for this, if you want such ceremonial language, is the doodle command, where you specify which canvas widget should be enabled to doodle, and in which color (defaults to black):

 proc doodle {w {color black}} {
    bind $w <1>         [list doodle'start %W %x %y $color]
    bind $w <B1-Motion> {doodle'move %W %x %y}
 }

It registers two bindings for the canvas, one (<1>) when the left mouse-button is clicked, and the other when the mouse is moved with button 1 (left) down. Both bindings just call one internal function each.

On left-click, a line item is created on the canvas in the specified fill color, but with no extent yet, as start and end points coincide. The item ID (a number assigned by the canvas) is kept in a global variable, as it will have to persist long after this procedure has returned:

 proc doodle'start {w x y color} {
        set ::_id [$w create line $x $y $x $y -fill $color]
 }

The left-motion procedure obtains the coordinates (alternating x and y) of the globally known doodling line object, appends the current coordinates to it, and makes this the new cooordinates - in other words, extends the line to the current mouse position:

 proc doodle'move {w x y} {
        $w coords $::_id [concat [$w coords $::_id] $x $y]
 }

That's all we need to implement doodling - now let's create a canvas to test it, and pack it so it can be drawn as big as you wish:

 pack [canvas .c -bg white] -fill both -expand 1

And this line turns on the doodle functionality created above (defaulting to black):

 doodle       .c

Add a binding for double-right-click/double-button-3, to clear the canvas (added by MG, Apr 29 04)

 bind .c <Double-3> {%W delete all}

See also Handwriting Word Recognizer