📄 combobox.tcl
字号:
} -width { $widgets(entry) configure -width $newValue $widgets(listbox) configure -width $newValue set options($option) $newValue } -xscrollcommand { $widgets(entry) configure -xscrollcommand $newValue set options($option) $newValue } } if {$updateVisual} {UpdateVisualAttributes $w} }}# ::combobox::UpdateVisualAttributes --## sets the visual attributes (foreground, background mostly) # based on the current state of the widget (normal/disabled, # editable/non-editable)## why a proc for such a simple thing? Well, in addition to the# various states of the widget, we also have to consider the # version of tk being used -- versions from 8.4 and beyond have# the notion of disabled foreground/background options for various# widgets. All of the permutations can get nasty, so we encapsulate# it all in one spot.## note also that we don't handle all visual attributes here; just# the ones that depend on the state of the widget. The rest are # handled on a case by case basis## Arguments:# w widget pathname## Returns:# empty stringproc ::combobox::UpdateVisualAttributes {w} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {$options(-state) == "normal"} { set foreground $options(-foreground) set background $options(-background) } elseif {$options(-state) == "disabled"} { set foreground $options(-disabledforeground) set background $options(-disabledbackground) } $widgets(entry) configure -foreground $foreground -background $background $widgets(listbox) configure -foreground $foreground -background $background $widgets(button) configure -foreground $foreground $widgets(frame) configure -background $background # we need to set the disabled colors in case our widget is disabled. # We could actually check for disabled-ness, but we also need to # check whether we're enabled but not editable, in which case the # entry widget is disabled but we still want the enabled colors. It's # easier just to set everything and be done with it. if {$::tcl_version >= 8.4} { $widgets(entry) configure \ -disabledforeground $foreground \ -disabledbackground $background $widgets(button) configure -disabledforeground $foreground $widgets(listbox) configure -disabledforeground $foreground }}# ::combobox::SetValue --## sets the value of the combobox and calls the -command, # if defined## Arguments:## w widget pathname# newValue the new value of the combobox## Returns## Empty stringproc ::combobox::SetValue {w newValue} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options upvar ::combobox::${w}::ignoreTrace ignoreTrace upvar ::combobox::${w}::oldValue oldValue if {[info exists options(-textvariable)] \ && [string length $options(-textvariable)] > 0} { set variable ::$options(-textvariable) set $variable $newValue } else { set oldstate [$widgets(entry) cget -state] $widgets(entry) configure -state normal $widgets(entry) delete 0 end $widgets(entry) insert 0 $newValue $widgets(entry) configure -state $oldstate } # set our internal textvariable; this will cause any public # textvariable (ie: defined by the user) to be updated as # well# set ::combobox::${w}::entryTextVariable $newValue # redefine our concept of the "old value". Do it before running # any associated command so we can be sure it happens even # if the command somehow fails. set oldValue $newValue # call the associated command. The proc will handle whether or # not to actually call it, and with what args CallCommand $w $newValue return ""}# ::combobox::CallCommand --## calls the associated command, if any, appending the new# value to the command to be called.## Arguments:## w widget pathname# newValue the new value of the combobox## Returns## empty stringproc ::combobox::CallCommand {w newValue} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options # call the associated command, if defined and -commandstate is # set to "normal" if {$options(-commandstate) == "normal" && \ [string length $options(-command)] > 0} { set args [list $widgets(this) $newValue] uplevel \#0 $options(-command) $args }}# ::combobox::GetBoolean --## returns the value of a (presumably) boolean string (ie: it should# do the right thing if the string is "yes", "no", "true", 1, etc## Arguments:## value value to be converted # errorValue a default value to be returned in case of an error## Returns:## a 1 or zero, or the value of errorValue if the string isn't# a proper boolean valueproc ::combobox::GetBoolean {value {errorValue 1}} { if {[catch {expr {([string trim $value])?1:0}} res]} { return $errorValue } else { return $res }}# ::combobox::convert --## public routine to convert %x, %y and %W binding substitutions.# Given an x, y and or %W value relative to a given widget, this# routine will convert the values to be relative to the combobox# widget. For example, it could be used in a binding like this:## bind .combobox <blah> {doSomething [::combobox::convert %W -x %x]}## Note that this procedure is *not* exported, but is intended for# public use. It is not exported because the name could easily # clash with existing commands. ## Arguments:## w a widget path; typically the actual result of a %W # substitution in a binding. It should be either a# combobox widget or one of its subwidgets## args should one or more of the following arguments or # pairs of arguments:## -x <x> will convert the value <x>; typically <x> will# be the result of a %x substitution# -y <y> will convert the value <y>; typically <y> will# be the result of a %y substitution# -W (or -w) will return the name of the combobox widget# which is the parent of $w## Returns:## a list of the requested values. For example, a single -w will# result in a list of one items, the name of the combobox widget.# Supplying "-x 10 -y 20 -W" (in any order) will return a list of# three values: the converted x and y values, and the name of # the combobox widget.proc ::combobox::convert {w args} { set result {} if {![winfo exists $w]} { error "window \"$w\" doesn't exist" } while {[llength $args] > 0} { set option [lindex $args 0] set args [lrange $args 1 end] switch -exact -- $option { -x { set value [lindex $args 0] set args [lrange $args 1 end] set win $w while {[winfo class $win] != "Combobox"} { incr value [winfo x $win] set win [winfo parent $win] if {$win == "."} break } lappend result $value } -y { set value [lindex $args 0] set args [lrange $args 1 end] set win $w while {[winfo class $win] != "Combobox"} { incr value [winfo y $win] set win [winfo parent $win] if {$win == "."} break } lappend result $value } -w - -W { set win $w while {[winfo class $win] != "Combobox"} { set win [winfo parent $win] if {$win == "."} break; } lappend result $win } } } return $result}# ::combobox::Canonize --## takes a (possibly abbreviated) option or command name and either # returns the canonical name or an error## Arguments:## w widget pathname# object type of object to canonize; must be one of "command",# "option", "scan command" or "list command"# opt the option (or command) to be canonized## Returns:## Returns either the canonical form of an option or command,# or raises an error if the option or command is unknown or# ambiguous.proc ::combobox::Canonize {w object opt} { variable widgetOptions variable columnOptions variable widgetCommands variable listCommands variable scanCommands switch $object { command { if {[lsearch -exact $widgetCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $widgetCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } {list command} { if {[lsearch -exact $listCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $listCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } {scan command} { if {[lsearch -exact $scanCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $scanCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } option { if {[info exists widgetOptions($opt)] \ && [llength $widgetOptions($opt)] == 2} { return $opt } set list [array names widgetOptions] set matches [array names widgetOptions ${opt}*] } } if {[llength $matches] == 0} { set choices [HumanizeList $list] error "unknown $object \"$opt\"; must be one of $choices" } elseif {[llength $matches] == 1} { set opt [lindex $matches 0] # deal with option aliases switch $object { option { set opt [lindex $matches 0] if {[llength $widgetOptions($opt)] == 1} { set opt $widgetOptions($opt) } } } return $opt } else { set choices [HumanizeList $list] error "ambiguous $object \"$opt\"; must be one of $choices" }}# ::combobox::HumanizeList --## Returns a human-readable form of a list by separating items# by columns, but separating the last two elements with "or"# (eg: foo, bar or baz)## Arguments:## list a valid tcl list## Results:## A string which as all of the elements joined with ", " or # the word " or "proc ::combobox::HumanizeList {list} { if {[llength $list] == 1} { return [lindex $list 0] } else { set list [lsort $list] set secondToLast [expr {[llength $list] -2}] set most [lrange $list 0 $secondToLast] set last [lindex $list end] return "[join $most {, }] or $last" }}# This is some backwards-compatibility code to handle TIP 44# (http://purl.org/tcl/tip/44.html). For all private tk commands# used by this widget, we'll make duplicates of the procs in the# combobox namespace. ## I'm not entirely convinced this is the right thing to do. I probably# shouldn't even be using the private commands. Then again, maybe the# private commands really should be public. Oh well; it works so it# must be OK...foreach command {TabToWindow CancelRepeat ListboxUpDown} { if {[llength [info commands ::combobox::tk$command]] == 1} break; set tmp [info commands tk$command] set proc ::combobox::tk$command if {[llength [info commands tk$command]] == 1} { set command [namespace which [lindex $tmp 0]] proc $proc {args} "uplevel $command \$args" } else { if {[llength [info commands ::tk::$command]] == 1} { proc $proc {args} "uplevel ::tk::$command \$args" } }}# end of combobox.tcl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -