# make sure listbox can take keyboard focus # (also enables cursor, PgUp/Dn etc.) bind $listbox <1> [list focus $listbox] # bind keyboard events to a handler proc bind $listbox <Any-Key> {listbox:match %W %A} proc listbox:match {w key} { if [regexp {[-A-Za-z0-9]} $key] { set n 0 foreach i [$w get 0 end] { # pity I'm still on 8.0.5, else I'd say -nocase if [string match $key* $i] { $w see $n $w selection clear 0 end $w selection set $n break } else { incr n } } } }Left-Click once on a listbox to give it focus (should get a highlighted border). Keys from the set specified in regexp make selection and view jump to the first occurence of the key.--Here's a version I use, which handles multiple characters. It requires something like this first:
bind $w <KeyPress> "dialog::a_key $w.frame.list %A"Then the following procedure handles everything -Vince.
## # ------------------------------------------------------------------------- # # "dialog::a_key" -- # # When the user presses a straightforward key in a dialog, this procedure # is called. If the first item in the dialog is suitable for keyboard # matching (e.g. it is a popup menu or a listbox), we try to match # the item the user is spelling out. # ------------------------------------------------------------------------- ## proc dialog::a_key {w key} { variable string_so_far #puts stdout "$w $key [winfo class $w]" if {[lsearch -exact [list Menubutton Listbox] [winfo class $w]] == -1} { return } append string_so_far $key #puts stderr $string_so_far after cancel [list set dialog::string_so_far ""] after 1000 [list set dialog::string_so_far ""] switch -- [winfo class $w] { "Menubutton" { set m [$w cget -menu] set last [$m index end] for {set i 0} {$i < $last} {incr i} { regsub -all " " [string tolower [$m entrycget $i -label]] "" item if {[string first $string_so_far $item] == 0} { $m invoke $i return } } } "Listbox" { set last [$w index end] for {set i 0} {$i < $last} {incr i} { regsub -all " " [string tolower [$w get $i]] "" item if {[string first $string_so_far $item] == 0} { set cur [$w curselection] if {[llength $cur]} { eval $w selection clear $cur } $w selection set $i $w see $i return } } } }}
I did a quick and dirty version of this with bindings. It's case sensitive and only works well with a sorted listbox. Very simple to make it work with letters other than the first.
set l .listbox foreach letter {a b c d e f g h i j k l m n o p q r s t u v w x y z} { bind $l <KeyPress-$letter> "set a \[lsearch -glob \[$l get 0 end\] $letter*] \;\ $l selection clear 0 end \;\ $l selection set \$a \; $l see \$a" }
MHo 2008-10-03: I wonder if it's possible to highlight the 'hotkey' in every listbox item. I fear the answer is no...
Tk examples - Arts and crafts of Tcl-Tk programming - Category GUI