📄 combobox.tcl
字号:
# ----------------------------------------------------------------------------proc ComboBox::_create_popup { path } { set shell $path.shell if {[winfo exists $shell]} { return } set lval [Widget::cget $path -values] set h [Widget::cget $path -height] set bw [Widget::cget $path -bwlistbox] if { $h <= 0 } { set len [llength $lval] if { $len < 3 } { set h 3 } elseif { $len > 10 } { set h 10 } else { set h $len } } if { $::tcl_platform(platform) == "unix" } { set sbwidth 11 } else { set sbwidth 15 } toplevel $shell -relief solid -bd 1 wm withdraw $shell update idletasks wm overrideredirect $shell 1 wm transient $shell [winfo toplevel $path] wm withdraw $shell catch { wm attributes $shell -topmost 1 } set sw [ScrolledWindow $shell.sw -managed 0 -size $sbwidth -ipad 0] if {$bw} { set listb [ListBox $shell.listb \ -relief flat -borderwidth 0 -highlightthickness 0 \ -selectmode single -selectfill 1 -autofocus 0 -height $h \ -font [Widget::cget $path -font] \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground]] set values [Widget::cget $path -values] set images [Widget::cget $path -images] foreach value $values image $images { $listb insert end #auto -text $value -image $image } $listb bindText <1> "ComboBox::_select $path" $listb bindImage <1> "ComboBox::_select $path" if {[Widget::cget $path -hottrack]} { $listb bindText <Enter> [list $listb selection set] $listb bindImage <Enter> [list $listb selection set] } } else { set listb [listbox $shell.listb \ -relief flat -borderwidth 0 -highlightthickness 0 \ -exportselection false \ -font [Widget::cget $path -font] \ -height $h \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground] \ -listvariable [Widget::varForOption $path -values]] ::bind $listb <ButtonRelease-1> [list ComboBox::_select $path @%x,%y] if {[Widget::cget $path -hottrack]} { bindtags $listb [concat [bindtags $listb] ListBoxHotTrack] } } pack $sw -fill both -expand yes $sw setwidget $listb ::bind $listb <Return> "ComboBox::_select $path \[%W curselection]" ::bind $listb <Escape> [list ComboBox::_unmapliste $path] ::bind $listb <FocusOut> [list ComboBox::_focus_out $path]}proc ComboBox::_recreate_popup { path } { variable background variable foreground set shell $path.shell set lval [Widget::cget $path -values] set h [Widget::cget $path -height] set bw [Widget::cget $path -bwlistbox] if { $h <= 0 } { set len [llength $lval] if { $len < 3 } { set h 3 } elseif { $len > 10 } { set h 10 } else { set h $len } } if { $::tcl_platform(platform) == "unix" } { set sbwidth 11 } else { set sbwidth 15 } _create_popup $path if {![Widget::cget $path -editable]} { if {[info exists background]} { $path.e configure -bg $background $path.e configure -fg $foreground unset background unset foreground } } set listb $shell.listb destroy $shell.sw set sw [ScrolledWindow $shell.sw -managed 0 -size $sbwidth -ipad 0] $listb configure \ -height $h \ -font [Widget::cget $path -font] \ -bg [Widget::cget $path -entrybg] \ -fg [Widget::cget $path -foreground] \ -selectbackground [Widget::cget $path -selectbackground] \ -selectforeground [Widget::cget $path -selectforeground] pack $sw -fill both -expand yes $sw setwidget $listb raise $listb}# ----------------------------------------------------------------------------# Command ComboBox::_mapliste# ----------------------------------------------------------------------------proc ComboBox::_mapliste { path } { set listb $path.shell.listb if {[winfo exists $path.shell] && [string equal [wm state $path.shell] "normal"]} { _unmapliste $path return } if { [Widget::cget $path -state] == "disabled" } { return } if { [set cmd [Widget::getMegawidgetOption $path -postcommand]] != "" } { uplevel \#0 $cmd } if { ![llength [Widget::getMegawidgetOption $path -values]] } { return } _recreate_popup $path ArrowButton::configure $path.a -relief sunken update set bw [Widget::cget $path -bwlistbox] $listb selection clear 0 end set values [Widget::getMegawidgetOption $path -values] set curval [Entry::cget $path.e -text] if { [set idx [lsearch -exact $values $curval]] != -1 || [set idx [lsearch -exact $values "$curval*"]] != -1 } { if {$bw} { set idx [$listb items $idx] } else { $listb activate $idx } $listb selection set $idx $listb see $idx } else { set idx 0 if {$bw} { set idx [$listb items 0] } else { $listb activate $idx } $listb selection set $idx $listb see $idx } set width [Widget::cget $path -listboxwidth] if {!$width} { set width [winfo width $path] } BWidget::place $path.shell $width 0 below $path wm deiconify $path.shell raise $path.shell BWidget::focus set $listb BWidget::grab global $path}# ----------------------------------------------------------------------------# Command ComboBox::_unmapliste# ----------------------------------------------------------------------------proc ComboBox::_unmapliste { path {refocus 1} } { if {[winfo exists $path.shell] && \ [string equal [wm state $path.shell] "normal"]} { BWidget::grab release $path BWidget::focus release $path.shell.listb $refocus # Update now because otherwise [focus -force...] makes the app hang! if {$refocus} { update focus -force $path.e } wm withdraw $path.shell ArrowButton::configure $path.a -relief raised }}# ----------------------------------------------------------------------------# Command ComboBox::_select# ----------------------------------------------------------------------------proc ComboBox::_select { path index } { set index [$path.shell.listb index $index] _unmapliste $path if { $index != -1 } { if { [setvalue $path @$index] } { set cmd [Widget::getMegawidgetOption $path -modifycmd] if { $cmd != "" } { uplevel \#0 $cmd } } } $path.e selection clear $path.e selection range 0 end}# ----------------------------------------------------------------------------# Command ComboBox::_modify_value# ----------------------------------------------------------------------------proc ComboBox::_modify_value { path direction } { if { [setvalue $path $direction] } { if { [set cmd [Widget::getMegawidgetOption $path -modifycmd]] != "" } { uplevel \#0 $cmd } }}# ----------------------------------------------------------------------------# Command ComboBox::_expand# ----------------------------------------------------------------------------proc ComboBox::_expand {path} { set values [Widget::getMegawidgetOption $path -values] if {![llength $values]} { bell return 0 } set found {} set curval [Entry::cget $path.e -text] set curlen [$path.e index insert] if {$curlen < [string length $curval]} { # we are somewhere in the middle of a string. # if the full value matches some string in the listbox, # reorder values to start matching after that string. set idx [lsearch -exact $values $curval] if {$idx >= 0} { set values [concat [lrange $values [expr {$idx+1}] end] \ [lrange $values 0 $idx]] } } if {$curlen == 0} { set found $values } else { foreach val $values { if {[string equal -length $curlen $curval $val]} { lappend found $val } } } if {[llength $found]} { Entry::configure $path.e -text [lindex $found 0] if {[llength $found] > 1} { set best [_best_match $found [string range $curval 0 $curlen]] set blen [string length $best] $path.e icursor $blen $path.e selection range $blen end } } else { bell } return [llength $found]}# best_match --# finds the best unique match in a list of names# The extra $e in this argument allows us to limit the innermost loop a# little further.# Arguments:# l list to find best unique match in# e currently best known unique match# Returns:# longest unique match in the list#proc ComboBox::_best_match {l {e {}}} { set ec [lindex $l 0] if {[llength $l]>1} { set e [string length $e]; incr e -1 set ei [string length $ec]; incr ei -1 foreach l $l { while {$ei>=$e && [string first $ec $l]} { set ec [string range $ec 0 [incr ei -1]] } } } return $ec}# possibly faster#proc match {string1 string2} {# set i 1# while {[string equal -length $i $string1 $string2]} { incr i }# return [string range $string1 0 [expr {$i-2}]]#}#proc matchlist {list} {# set list [lsort $list]# return [match [lindex $list 0] [lindex $list end]]#}# ----------------------------------------------------------------------------# Command ComboBox::_traverse_in# Called when widget receives keyboard focus due to keyboard traversal.# ----------------------------------------------------------------------------proc ComboBox::_traverse_in { path } { if {[$path.e selection present] != 1} { # Autohighlight the selection, but not if one existed $path.e selection range 0 end }}# ----------------------------------------------------------------------------# Command ComboBox::_focus_out# ----------------------------------------------------------------------------proc ComboBox::_focus_out { path } { if {[focus] == ""} { # we lost focus to some other app, make sure we drop the listbox return [_unmapliste $path 0] }}proc ComboBox::_auto_complete { path key } { ## Anything that is all lowercase is either a letter, number ## or special key we're ok with. Everything else is a ## functional key of some kind. if {[string tolower $key] != $key} { return } set text [string map [list {[} {\[} {]} {\]}] [$path.e get]] if {[string equal $text ""]} { return } set values [Widget::cget $path -values] set x [lsearch $values $text*] if {$x < 0} { return } set idx [$path.e index insert] $path.e configure -text [lindex $values $x] $path.e icursor $idx $path.e select range insert end}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -