📄 combobox.tcl
字号:
# (even if it is not presently visible). # # this isn't strictly necessary if the window is already # mapped, but we'll go ahead and set the geometry here # since its harmless and *may* actually reset the geometry # to something better in some weird case. set geometry [::combobox::ComputeGeometry $widgets(this)] wm geometry $widgets(dropdown) $geometry update idletasks # if we are already open, there's nothing else to do if {[winfo ismapped $widgets(dropdown)]} { return 0 } # save the widget that currently has the focus; we'll restore # the focus there when we're done set oldFocus [focus] # ok, tweak the visual appearance of things and # make the list pop up $widgets(button) configure -relief sunken wm deiconify $widgets(dropdown) update idletasks raise $widgets(dropdown) # force focus to the entry widget so we can handle keypress # events for traversal focus -force $widgets(entry) # select something by default, but only if its an # exact match... ::combobox::Find $widgets(this) 1 # save the current grab state for the display containing # this widget. We'll restore it when we close the dropdown # list set status "none" set grab [grab current $widgets(this)] if {$grab != ""} {set status [grab status $grab]} set oldGrab [list $grab $status] unset grab status # *gasp* do a global grab!!! Mom always told me not to # do things like this, but sometimes a man's gotta do # what a man's gotta do. grab -global $widgets(this) # fake the listbox into thinking it has focus. This is # necessary to get scanning initialized properly in the # listbox. event generate $widgets(listbox) <B1-Enter> return 1 } close { # if we are already closed, don't do anything... if {![winfo ismapped $widgets(dropdown)]} { return 0 } # restore the focus and grab, but ignore any errors... # we're going to be paranoid and release the grab before # trying to set any other grab because we really really # really want to make sure the grab is released. catch {focus $oldFocus} result catch {grab release $widgets(this)} catch { set status [lindex $oldGrab 1] if {$status == "global"} { grab -global [lindex $oldGrab 0] } elseif {$status == "local"} { grab [lindex $oldGrab 0] } unset status } # hides the listbox $widgets(button) configure -relief raised wm withdraw $widgets(dropdown) # select the data in the entry widget. Not sure # why, other than observation seems to suggest that's # what windows widgets do. set editable [::combobox::GetBoolean $options(-editable)] if {$editable} { $widgets(entry) selection range 0 end $widgets(button) configure -relief raised } # magic tcl stuff (see tk.tcl in the distribution # lib directory) ::combobox::tkCancelRepeat return 1 } cget { if {[llength $args] != 1} { error "wrong # args: should be $w cget option" } set opt [::combobox::Canonize $w option [lindex $args 0]] if {$opt == "-value"} { set result [$widgets(entry) get] } else { set result $options($opt) } } configure { set result [eval ::combobox::Configure {$w} $args] } default { error "bad option \"$command\"" } } return $result}# ::combobox::Configure --## Implements the "configure" widget subcommand## Arguments:## w widget pathname# args zero or more option/value pairs (or a single option)## Results:# # Performs typcial "configure" type requests on the widgetproc ::combobox::Configure {w args} { variable widgetOptions variable defaultEntryCursor upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {[llength $args] == 0} { # hmmm. User must be wanting all configuration information # note that if the value of an array element is of length # one it is an alias, which needs to be handled slightly # differently set results {} foreach opt [lsort [array names widgetOptions]] { if {[llength $widgetOptions($opt)] == 1} { set alias $widgetOptions($opt) set optName $widgetOptions($alias) lappend results [list $opt $optName] } else { set optName [lindex $widgetOptions($opt) 0] set optClass [lindex $widgetOptions($opt) 1] set default [option get $w $optName $optClass] if {[info exists options($opt)]} { lappend results [list $opt $optName $optClass \ $default $options($opt)] } else { lappend results [list $opt $optName $optClass \ $default ""] } } } return $results } # one argument means we are looking for configuration # information on a single option if {[llength $args] == 1} { set opt [::combobox::Canonize $w option [lindex $args 0]] set optName [lindex $widgetOptions($opt) 0] set optClass [lindex $widgetOptions($opt) 1] set default [option get $w $optName $optClass] set results [list $opt $optName $optClass \ $default $options($opt)] return $results } # if we have an odd number of values, bail. if {[expr {[llength $args]%2}] == 1} { # hmmm. An odd number of elements in args error "value for \"[lindex $args end]\" missing" } # Great. An even number of options. Let's make sure they # are all valid before we do anything. Note that Canonize # will generate an error if it finds a bogus option; otherwise # it returns the canonical option name foreach {name value} $args { set name [::combobox::Canonize $w option $name] set opts($name) $value } # process all of the configuration options # some (actually, most) options require us to # do something, like change the attributes of # a widget or two. Here's where we do that... # # note that the handling of disabledforeground and # disabledbackground is a little wonky. First, we have # to deal with backwards compatibility (ie: tk 8.3 and below # didn't have such options for the entry widget), and # we have to deal with the fact we might want to disable # the entry widget but use the normal foreground/background # for when the combobox is not disabled, but not editable either. set updateVisual 0 foreach option [array names opts] { set newValue $opts($option) if {[info exists options($option)]} { set oldValue $options($option) } switch -- $option { -buttonbackground { $widgets(button) configure -background $newValue } -background { set updateVisual 1 set options($option) $newValue } -borderwidth { $widgets(frame) configure -borderwidth $newValue set options($option) $newValue } -command { # nothing else to do... set options($option) $newValue } -commandstate { # do some value checking... if {$newValue != "normal" && $newValue != "disabled"} { set options($option) $oldValue set message "bad state value \"$newValue\";" append message " must be normal or disabled" error $message } set options($option) $newValue } -cursor { $widgets(frame) configure -cursor $newValue $widgets(entry) configure -cursor $newValue $widgets(listbox) configure -cursor $newValue set options($option) $newValue } -disabledforeground { set updateVisual 1 set options($option) $newValue } -disabledbackground { set updateVisual 1 set options($option) $newValue } -dropdownwidth { set options($option) $newValue } -editable { set updateVisual 1 if {$newValue} { # it's editable... $widgets(entry) configure \ -state normal \ -cursor $defaultEntryCursor } else { $widgets(entry) configure \ -state disabled \ -cursor $options(-cursor) } set options($option) $newValue } -elementborderwidth { $widgets(button) configure -borderwidth $newValue $widgets(vsb) configure -borderwidth $newValue $widgets(dropdown) configure -borderwidth $newValue set options($option) $newValue } -font { $widgets(entry) configure -font $newValue $widgets(listbox) configure -font $newValue set options($option) $newValue } -foreground { set updateVisual 1 set options($option) $newValue } -height { $widgets(listbox) configure -height $newValue HandleScrollbar $w set options($option) $newValue } -highlightbackground { $widgets(frame) configure -highlightbackground $newValue set options($option) $newValue } -highlightcolor { $widgets(frame) configure -highlightcolor $newValue set options($option) $newValue } -highlightthickness { $widgets(frame) configure -highlightthickness $newValue set options($option) $newValue } -image { if {[string length $newValue] > 0} { puts "old button width: [$widgets(button) cget -width]" $widgets(button) configure \ -image $newValue \ -width [expr {[image width $newValue] + 2}] puts "new button width: [$widgets(button) cget -width]" } else { $widgets(button) configure -image ::combobox::bimage } set options($option) $newValue } -listvar { if {[catch {$widgets(listbox) cget -listvar}]} { return -code error \ "-listvar not supported with this version of tk" } $widgets(listbox) configure -listvar $newValue set options($option) $newValue } -maxheight { # ComputeGeometry may dork with the actual height # of the listbox, so let's undork it $widgets(listbox) configure -height $options(-height) HandleScrollbar $w set options($option) $newValue } -opencommand { # nothing else to do... set options($option) $newValue } -relief { $widgets(frame) configure -relief $newValue set options($option) $newValue } -selectbackground { $widgets(entry) configure -selectbackground $newValue $widgets(listbox) configure -selectbackground $newValue set options($option) $newValue } -selectborderwidth { $widgets(entry) configure -selectborderwidth $newValue $widgets(listbox) configure -selectborderwidth $newValue set options($option) $newValue } -selectforeground { $widgets(entry) configure -selectforeground $newValue $widgets(listbox) configure -selectforeground $newValue set options($option) $newValue } -state { if {$newValue == "normal"} { set updateVisual 1 # it's enabled set editable [::combobox::GetBoolean \ $options(-editable)] if {$editable} { $widgets(entry) configure -state normal $widgets(entry) configure -takefocus 1 } # note that $widgets(button) is actually a label, # not a button. And being able to disable labels # wasn't possible until tk 8.3. (makes me wonder # why I chose to use a label, but that answer is # lost to antiquity) if {[info patchlevel] >= 8.3} { $widgets(button) configure -state normal } } elseif {$newValue == "disabled"} { set updateVisual 1 # it's disabled $widgets(entry) configure -state disabled $widgets(entry) configure -takefocus 0 # note that $widgets(button) is actually a label, # not a button. And being able to disable labels # wasn't possible until tk 8.3. (makes me wonder # why I chose to use a label, but that answer is # lost to antiquity) if {$::tcl_version >= 8.3} { $widgets(button) configure -state disabled } } else { set options($option) $oldValue set message "bad state value \"$newValue\";" append message " must be normal or disabled" error $message } set options($option) $newValue } -takefocus { $widgets(entry) configure -takefocus $newValue set options($option) $newValue } -textvariable { $widgets(entry) configure -textvariable $newValue set options($option) $newValue } -value {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -