xlistbox

Richard Suchenwirth 2007-09-28 - Installing Visual Studio 8, I found a listbox with some buttons to insert, delete, or move up or down items, and as I was waiting for a lengthy build, of course I had to try this in Tcl too :^)

WikiDbImage xlistbox.JPG

For the "insert" function, a little overrideredirect toplevel with an entry is overlaid. This is however not very robust: pixel geometry needed to be tweaked (and is probably not right for other windowing themes), and it is only destroyed when the user hits <Return>. If he doesn't, multiple of those may be scattered over the screen... Improvement hints are very welcome. AEC Couldn't you bind the entry widget to the <FocusOut> event and destroy the toplevel? Also couldn't you simply use the place geometry manager and place an entry widget rather than using the overrideredirect toplevel? - RS: Oh yes, thanks! Fixed the insert and rewrite methods accordingly.

 proc xlb'delete w {
    set sel [$w curselection]
    $w delete $sel
    if {$sel==[$w size]} {incr sel -1}
    $w selection set $sel
 }
 proc xlb'insert w {
    set sel [$w curselection]
    if {$sel eq ""} {set sel 0}
    $w insert $sel ""
    $w selection clear 0 end
    $w selection set $sel
    foreach {x0 y0 x1 y1} [$w bbox $sel] break
    destroy $w.e
    place [entry $w.e -textvariable $w] -x [expr {$x0-4}] -y [expr {$y0-4}]
    focus $w.e
    set ::$w ""
    bind $w.e <Return> [list xlb'rewrite $w $sel]
 }
 proc xlb'rewrite {w sel} {
    global $w
    $w delete $sel
    $w insert $sel [set $w]
    $w selection set $sel
    destroy $w.e
 }
 proc xlb'move {w offset} {
    set sel [$w curselection]
    if {$sel ne "" && ($offset==-1 && $sel>0 || $offset==1 && $sel<[$w size]-1)} {
        set it [$w get $sel]
        $w delete $sel
        incr sel $offset
        $w insert $sel $it
        $w selection set $sel
    }
 }
#-- Test and demo:
 pack [frame .f] -anchor e
 button .f.+ -width 2 -text + -command {xlb'insert .l}
 button .f.x -width 2 -text x -command {xlb'delete .l}
 button .f.up -width 2 -text \u2191 -command {xlb'move .l -1} 
 button .f.dn -width 2 -text \u2193 -command {xlb'move .l 1}
 eval pack [winfo children .f] -side left

 pack [listbox .l]
 .l insert end foo bar grill baz wibble

AMG: I think that's the first time I've ever seen [place] used for good, not evil. :^)

MG spots a few minor bugs while playing around with this:

  • If you delete an element while you have the entry widget displayed to add a new one, you can end up with an element hidden behind the entry widget
  • If you click to add an element, type in a name, then click to add another element (without pressing return to submit the first one), the first one is added with no label. Would it be better to either not add it, or use whatever is currently in the entry widget, rather than adding it with no label?
  • If you click to add a new element, then click an element to select it, then press return to finalise adding the new element, you end up with two elements selected.