SO While working on a set of indicator lights for one of my current projects, it occurred to me that I could make a simple sample, using the canvas widget, that could prove extremely useful to beginners and newbies. (I know I could have used such an example not so long ago.)
Among other things, it contains a simple sample of a global array, accessing the array via the use of upvar, creating some simple shapes on a canvas, a simple switch proc, a simple proc for generating a pseudo-random int, and a simple example of using after, to drive the demonstration. All of these are questions are regularly asked on clt.
I sincerely hope that someone finds it useful. Comments are welcome and appreciated.
#Wednesday, May 29, 2002 22:33:52 #define a global array of colors #feel free to edit the colors, as my colorvision is #rather unique... set colorAr(dkblue) #160071 set colorAr(brtblue) #7ef4fe set colorAr(dkgreen) #3e532b set colorAr(brtgreen) #92fe7e set colorAr(dkyellow) #b9bd1a set colorAr(brtyellow) #ffff4f set colorAr(dkred) #75222b set colorAr(brtred) #ff004d #create a canvas pack [canvas .c -width 180 -height 30 -bg grey -relief groove -bd 2] #draw some ojbects in the canvas, give them a tag name #and default fill color .c create oval 20 28 40 8 -tag blueled -fill $colorAr(dkblue) .c create rectangle 60 28 80 8 -tag greenled -fill $colorAr(dkgreen) .c create polygon 100 28 115 8 130 28 -outline black \ -tag yellowled -fill $colorAr(dkyellow) .c create line 144 18 168 18 -arrow last -width 12 \ -tag redled -fill $colorAr(dkred) #turn on the lights... proc greenlight { arrayname } { upvar #0 $arrayname thisArray .c itemconfigure blueled -fill $thisArray(dkblue) .c itemconfigure yellowled -fill $thisArray(dkyellow) .c itemconfigure redled -fill $thisArray(dkred) .c itemconfigure greenled -fill $thisArray(brtgreen) } proc bluelight { arrayname } { upvar #0 $arrayname thisArray .c itemconfigure yellowled -fill $thisArray(dkyellow) .c itemconfigure redled -fill $thisArray(dkred) .c itemconfigure greenled -fill $thisArray(dkgreen) .c itemconfigure blueled -fill $thisArray(brtblue) } proc yellowlight { arrayname } { upvar #0 $arrayname thisArray .c itemconfigure redled -fill $thisArray(dkred) .c itemconfigure greenled -fill $thisArray(dkgreen) .c itemconfigure blueled -fill $thisArray(dkblue) .c itemconfigure yellowled -fill $thisArray(brtyellow) } proc redlight { arrayname } { upvar #0 $arrayname thisArray .c itemconfigure greenled -fill $thisArray(dkgreen) .c itemconfigure blueled -fill $thisArray(dkblue) .c itemconfigure yellowled -fill $thisArray(dkyellow) .c itemconfigure redled -fill $thisArray(brtred) } #a simple pseudo-random int proc - returns a value from #1 to upper limit proc random_int { upper_limit } { set myrand [expr int(rand() * $upper_limit + 1)] } #a proc to switch which light is on proc randomlight { } { set int [random_int 4] switch $int { 1 {greenlight colorAr} 2 {bluelight colorAr} 3 {yellowlight colorAr} 4 {redlight colorAr} } } #an after callback to drive this thing #un-commenting the bell line will help to show #how often the random_int proc repeats in such a limited range proc run { } { after 1000 run randomlight #bell } #set the window title wm title . "Shapes and Lights" wm deiconify . #call the run proc run
proc light { color arrayname } { set colors [ list dkyellow dkred dkgreen dkblue ] set i [ lsearch $colors dk$color ] set colors [ lreplace $colors $i ] lappend colors brt$color upvar #0 $arrayname thisArray foreach color $colors { .c itemconfigure ${color}led -fill $thisArray($color) } }
SOAs suggested by the above edit, we can certainly improve our little script by replacing four procs (bluelight, greenlight, yellowlight and redlight) with just one proc, light. I would go about it a little differently...
proc light {color arrayname} { set colorlist {blue green yellow red} upvar #0 $arrayname thisArray foreach index $colorlist { .c itemconfigure ${index}led -fill $thisArray(dk$index) } .c itemconfigure ${color}led -fill $thisArray(brt$color) } #which requires us to change our randomlight proc just a little proc randomlight { } { set int [random_int 4] switch $int { 1 {light green colorAr} 2 {light blue colorAr} 3 {light yellow colorAr} 4 {light red colorAr} } }
Perhaps someone else would care to comment on improving the original script?
RS: What you want here, is a random color from a list, so here's how I would do that - if such a proc is needed at all (and the function of colorAr is dubious):
proc randomlight {} {light [lpick {green blue yellow red}] colorAr}
where
proc lpick list {lindex $list [expr {int(rand()*[llength $list])}]}