Tcl/Tk LstBox width in CombBox

流过昼夜 提交于 2020-01-24 18:17:07

问题


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:


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



来源:https://stackoverflow.com/questions/17588455/tcl-tk-lstbox-width-in-combbox

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!