# 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

