#{fileheader} #--------------- # Boilerplate object builder package for Gnocl derived megawidgets. # Based upon approach used in Gnocl source code. #--------------- # USAGE: Substitute keywords "_prj_" and "_widget_" for unique project and object type identifier. #--------------- #!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" package require Gnocl #--------------- # lists of valid widget options, commands and components #--------------- # oo::class create _prj_:_widget_ { constructor {} { # declare variables to store data, settings and widget ids my variable container my variable but1 my variable but2 my variable parts my variable data set data "How Now Brown Cow" # create and assemble megawidget parts set container [gnocl::vBox] set but1 [gnocl::button -text HIDIHI -icon %#Help] set but2 [gnocl::button -text HODIHO -icon %#Stop] $container add $but1 $container add $but2 # retain a list of parts set parts [list container but1 but2] } destructor { my variable container $container delete } method getId {} { my variable container return $container } method class {} { return _widget_ } #--------------- # generic controller, directly access all elements of widget control method cmd { args } { my variable parts foreach var $parts { my variable $var } eval [set [lindex $args 0]] [lindex $args 1] [lrange $args 2 end] } method configure { args } { my variable parts foreach var $parts { my variable $var } eval [set [lindex $args 0]] configure [lrange $args 1 end] } method cget { args } { my variable parts foreach var $parts { my variable $var } eval [set [lindex $args 0]] cget [lrange $args 1 end] } # set or retrieve megawidget internal data method getData {} { my variable data return $data } method setData {val} { my variable data set data $val } # object operations, or specfic methods method tooltips { tt1 tt2 } { my variable parts foreach var $parts { my variable $var } $but1 configure -tooltip $tt1 $but2 configure -tooltip $tt2 } # manipulate internal data method tocaps {} { my variable data set data [string toupper $data] } } #=============== # DEMO #=============== proc demo {} { set b1 [_prj_:_widget_ new] puts [$b1 class] gnocl::window -child [$b1 getId] -title A -setSize 0.125 -x 200 $b1 configure but1 -onClicked { puts "HI %d" } -data PING $b1 configure but2 -onClicked { puts "HO %d" } -data PONG puts [$b1 cget but1 -data] $b1 tooltips "HI DI HI" "HO DI HO" puts [$b1 getData] $b1 tocaps puts [$b1 getData] set b2 [_prj_:_widget_ new] gnocl::window -child [$b2 getId] -title B -setSize 0.125 -x 400 $b2 destroy catch { $b2 configure but2 -onClicked { puts "HO %d" } -data PONG } {} } demo
AMG: It looks like those [eval]s can be written in terms of {*}:
eval [set [lindex $args 0]] [lindex $args 1] [lrange $args 2 end] {*}[set [lindex $args 0]] {*}[lrange $args 1 end]DKF: Interesting how you are bringing variables into the scope of the methods doing the delegation, but I think you can do it more simply:
method cmd { part subcommand args } { my variable parts if {$part ni $parts} { return -code error "no such part \"$part\"" } {*}[set [my varname $part]] $subcommand {*}$args }This has fewer hazards (and makes a nicer error message) and yet otherwise works the same in all sane cases. Anything where it doesn't... well you're probably better off writing a method then.