How can I configure the listbox component width in a combobox, so that it will fit to longest entry? The widget width itself (the entry component) can be short, but I'm looking for a way to configure the listbox component to be wider than the entry...
1 Answers
This is possible, but not without a bit of hacking ;)
You can find the implementation of combobox in combobox.tcl
(in my case /usr/share/tcltk/tk8.5/ttk/combobox.tcl
. There you see that if you have a combobox
set cb [ttk::combobox .cb -state readonly]
and invoke it, it creates the following internal widget structure:
$cb.popdown.f.l
popdown
is the toplevel that pops down if you click the combobox, f
a frame, and l
the actual listbox which contains your values. To fit the longest entry you need to modify the geometry of the popdown
toplevel.
We try to do so by binding a resize script to theButtonPress
event on the combobox, however, this does not work because by default the bindings are handled in the following order (output of puts [bindtags $cb]
):
.cb TCombobox . all
So first the events on the widget (.cb
) are handled, then the events on the class (TCombobox
), and then on the toplevel (.
) and finally the events that are bound to all widgets.
What this means is that when we click the combobox, first our resize script is executed, but then the popdown
toplevel does exist yet, because it will only be created when handling the class event.
The solution is to switch the event handling order for the widget and class:
bindtags $cb [list TCombobox $cb . all]
Now it should be working! Below a minimal proof of concept:
package require Tk
wm title . "Combobox Listbox resize"
wm geometry . "150x40"
grid columnconfigure . 0 -weight 1
set cb [ttk::combobox .cb -width 20 -state readonly]
grid $cb -row 1 -column 0
set cmd "$cb configure -values {abarsdhresntdaenstdsnthret erstihre reshterhstierht}"
$cb configure -postcommand $cmd
bind $cb <ButtonPress> changeGeomPopdown
bindtags $cb [list TCombobox $cb . all]
proc changeGeomPopdown { } {
global cb
scan [wm geometry $cb.popdown] "%dx%d+%d+%d" w h x y
wm geometry $cb.popdown "300x${h}+${x}+${y}"
}
To get the desired width you need to ask for the font of the listbox [1]:
$cb.popdown.f.l cget -font
Then use the font measure
command ([2]) on every string to determine the pixels you need to fit all entries. Don't forget to add a bit of padding to for a better look and to make sure the scrollbar doesn't overlap with your text.
NB: To avoid all kind of nasty stuff please make sure that this internal widget structure is in place before you try to modify it, the implementation of ttk::combobox
might change and then your program won't work anymore!
[1] http://www.tcl.tk/man/tcl8.5/TkCmd/listbox.htm#M16
[2] http://www.tcl.tk/man/tcl8.5/TkCmd/font.htm#M10

- 1,379
- 1
- 16
- 25
-
Perhaps a horizontal scroll bar would be simple workaround (even though not as nice as a perfectly sized selection list). – R Yoda Jan 06 '16 at 10:38