glennj Some time ago [L1 ], I because frustrated with Tk's default checkbutton. I wanted it to accept any boolean value [L2 ]. I ended up writing this package:
package require Tk package provide booleanCheckbutton 0.1 # create a checkbutton that selects when it's variable is set to # a boolean true value # # arguments: # widget - the widget "pathName" # args - list of checkbutton configuration options # # example: # set cb [booleanCheckbutton .bcb -textvariable bcbVal \ # -text "checkbutton label" -relief flat] # set bcbVal true # # Any errors will be propagated up to the caller. # namespace eval ::booleanCheckbutton { namespace export booleanCheckbutton variable varName variable traceCmd array set varName {} array set traceCmd {} } proc ::booleanCheckbutton::booleanCheckbutton {pathName args} { # create the checkbutton with the specified options eval [linsert $args 0 checkbutton $pathName] # set the namespace variables now that the widget command has been created variable varName variable traceCmd set varName($pathName) [$pathName cget -variable] set traceCmd($pathName) [list [namespace current]::selectIfTrue $pathName] # ensure the trace occurs in the global scope uplevel #0 [list trace add variable $varName($pathName) write $traceCmd($pathName)] # need to remove the variable trace if the checkbutton is deleted # i.e. if it's parent window is destroyed uplevel #0 [list trace add command $pathName delete [namespace current]::removeTrace] # trigger the trace for the current value of $varName, if it exists upvar #0 $varName($pathName) var if {[info exists var]} { uplevel #0 [list set $varName($pathName) $var] } return $pathName } proc ::booleanCheckbutton::selectIfTrue {widget varName arrayIndex op} { if {$op eq "write"} { if {$arrayIndex eq ""} { upvar #0 $varName var } else { upvar #0 ${varName}($arrayIndex) var } if {[string is boolean -strict $var] && $var} { set var [$widget cget -onvalue] } } } proc ::booleanCheckbutton::removeTrace {pathName args} { variable varName variable traceCmd uplevel #0 [list trace remove variable $varName($pathName) write $traceCmd($pathName)] uplevel #0 [list trace remove command $pathName delete [namespace current]::removeTrace] unset -nocomplain varName($pathName) traceCmd($pathName) } if 0 { # test package require Tk package require booleanCheckbutton namespace import ::booleanCheckbutton::booleanCheckbutton entry .e -textvar entry_value bind .e <Return> {set checkbutton_value $entry_value; set entry_value ""} booleanCheckbutton .c -variable checkbutton_value -textvariable checkbutton_value button .l -text "type a value, hit return, observe the checkbutton" pack .l .e .c }
glennj 20071202 - updated to fix an error in the test code, and placed package in a namespace
glennj 20090309 - updated to use arrays for namespace variables, to allow for more than one booleanCheckbutton per application