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