
The minimal megawidget edit
# --------------------------------
#
# a minimal multi listboxes megawidget
#
# --------------------------------
namespace eval multilist \
{
namespace export multilist
# -----------------
# the constructor
# -----------------
proc multilist {w args} \
{
variable {}
# variables
set ($w:yview) 0
set ($w:started) 0
set ($w:resizing) 0
# options
set lheight 20
set theight 20
set width1 20
set width2 20
set width3 20
set font {Courier -12}
set lcolor white
set tcolor gray90
array set titles {1 1 2 2 3 3}
foreach {key value} $args \
{
switch -glob -- $key \
{
-font { set font $value }
-lcolor { set lcolor $value }
-tcolor { set tcolor $value }
-lheight { set lheight $value }
-theight { set theight $value }
-titles { array set titles $value }
-width1 { set width1 $value }
-width2 { set width2 $value }
-width3 { set width3 $value }
}
}
set ($w:chwidth) [font measure $font 0]
set ($w:theight) $theight
# widgets
pack [frame $w] -fill both -expand 1
frame $w.t -cursor sb_h_double_arrow
frame $w.f -bg beige
set ty [expr {$theight / 2}]
foreach i {1 2 3} \
{
set width [set width$i]
set pwidth [expr {$width * $($w:chwidth)}]
canvas $w.t.l$i -width $pwidth -height $theight -bg $tcolor -bd 1 -relief ridge \
-highlightthickness 0 -cursor arrow
$w.t.l$i create text [expr {$pwidth / 2}] $ty -text $titles($i) -font $font
listbox $w.f.l$i -yscrollc [namespace code [list yscroll $w]] \
-font $font -width $width -height $lheight \
-bd 2 -relief groove -highlightthickness 0 \
-exportselection 0
}
scrollbar $w.vs -command [namespace code [list yview $w]]
grid $w.t -column 0 -row 0 -sticky nsew
grid $w.f -column 0 -row 1 -sticky nsew
grid $w.vs -column 1 -row 0 -rowspan 2 -sticky ns
grid $w.t.l1 -column 0 -row 0 -padx 1
grid $w.t.l2 -column 1 -row 0 -padx 1
grid $w.t.l3 -column 2 -row 0 -padx 1 -sticky ew
grid $w.f.l1 -column 0 -row 1 -sticky ns
grid $w.f.l2 -column 1 -row 1 -sticky ns
grid $w.f.l3 -column 2 -row 1 -sticky ewns
grid rowconfigure $w 1 -weight 1
grid columnconfigure $w 0 -weight 1
grid rowconfigure $w.t 1 -weight 1
grid columnconfigure $w.t 2 -weight 1
grid rowconfigure $w.f 1 -weight 1
grid columnconfigure $w.f 2 -weight 1
# bind the Motion event
bind $w.t <ButtonPress-1> [namespace code [list start $w %x]]
bind $w.t <ButtonRelease-1> [namespace code [list stop $w %x]]
bind $w.t <Motion> [namespace code [list resize $w %x]]
# bind the select events
bind $w.f.l1 <<ListboxSelect>> [namespace code [list synchro $w 1 2 3]]
bind $w.f.l2 <<ListboxSelect>> [namespace code [list synchro $w 2 3 1]]
bind $w.f.l3 <<ListboxSelect>> [namespace code [list synchro $w 3 1 2]]
# return ref
return $w
}
# -----------------
# the scroll procs
# -----------------
# called by a listbox
proc yscroll {w args} \
{
if {![winfo exists $w.vs]} { return }
eval [linsert $args 0 $w.vs set]
yview $w moveto [lindex [$w.vs get] 0]
}
# called by the scroll bar
proc yview {w args} \
{
variable {}
if {$($w:yview)} { return }
set ($w:yview) 1
foreach i {1 2 3} { eval $w.f.l$i yview $args }
set ($w:yview) 0
}
# called by a select event
proc synchro {w i1 i2 i3} \
{
set sel [$w.f.l$i1 cursel]
$w.f.l$i2 selection clear 0 end
$w.f.l$i3 selection clear 0 end
foreach item $sel { $w.f.l$i2 selection set $item }
foreach item $sel { $w.f.l$i3 selection set $item }
}
# -----------------
# the resize procs
# -----------------
# start resizing
proc start {w x} \
{
variable {}
set ($w:started) 1
set i 0
set ww 0
while {$ww < $x} \
{
incr i
incr ww [winfo width $w.f.l$i]
}
set ($w:i) $i
}
# stop resizing
proc stop {w x} { variable {}; set ($w:started) 0 }
# resize
proc resize {w x} \
{
variable {}
if {!$($w:started) || $($w:resizing) || $($w:i) == 0} { return }
set ($w:resizing) 1
set ww 0
set i 1
while {$i < $($w:i)} \
{
incr ww [winfo width $w.f.l$i]
incr i
}
set i $($w:i)
set lwidth [expr {($x - $ww) / $($w:chwidth)}]
set twidth [expr {$lwidth * $($w:chwidth)}]
$w.t.l$i config -width $twidth
$w.t.l$i coord all [expr {$twidth / 2}] [expr {$($w:theight) / 2}]
$w.f.l$i config -width $lwidth
update
set ($w:resizing) 0
}
}A demo edit
# =============
# demo
# =============
wm title . "multi listboxes"
# create the multilistbox
namespace import ::multilist::multilist
multilist .ml -width1 10 -width2 20 -width3 30 \
-titles {1 command 2 category 3 description} -tcolor beige
pack .ml -fill both -expand 1
# fill the multilistbox
# (data from ActiveState ActiveTcl 8.4.2.0 Help)
set data \
{
{{after} {Control Constructs} {Execute a command after a time delay}}
{{append} {Variables and Procedures} {Append to variable}}
{{array} {Variables and Procedures} {Manipulate array variables}}
{{bgerror} {Interpreter Routines} {Command invoked to process background errors}}
{{binary} {String Handling} {Insert and extract fields from binary strings}}
{{break} {Control Constructs} {Abort looping command}}
{{catch} {Control Constructs} {Evaluate script and trap exceptional returns}}
{{cd} {System Related} {Change working directory}}
{{clock} {System Related} {Obtain and manipulate time}}
{{close} {Output} {Close an open channel.}}
{{concat} {List Handling} {Join lists together}}
{{continue} {Control Constructs} {Skip to the next iteration of a loop}}
{{dde} {Platform-specific} {Execute a Dynamic Data Exchange command}}
{{encoding} {Library Procedures} {Manipulate encodings}}
{{eof} {Output} {Check for end of file condition on channel}}
{{error} {Control Constructs} {Generate an error}}
{{eval} {Control Constructs} {Evaluate a Tcl script}}
{{exec} {System Related} {Invoke subprocess(es)}}
{{exit} {System Related} {End the application}}
{{expr} {Expr} {Evaluate an expression}}
{{fblocked} {Output} {Test whether the last input operation exhausted all available input}}
{{fconfigure} {Output} {Set and get options on a channel}}
{{fcopy} {Output} {Copy data from one channel to another.}}
{{file} {Output} {Manipulate file names and attributes}}
{{fileevent} {Output} {Execute a script when a channel becomes readable or writable}}
{{flush} {Output} {Flush buffered output for a channel}}
{{for} {Control Constructs} {``For'' loop}}
{{foreach} {Control Constructs} {Iterate over all elements in one or more lists}}
{{format} {String Handling} {Format a string in the style of sprintf}}
{{gets} {Output} {Read a line from a channel}}
{{glob} {System Related} {Return names of files that match patterns}}
{{global} {Variables and Procedures} {Access global variables}}
{{history} {Interpreter Routines} {Manipulate the history list}}
{{http} {Library Procedures} {Client-side implementation of the HTTP/1.0 protocol.}}
{{if} {Control Constructs} {Execute scripts conditionally}}
{{incr} {Variables and Procedures} {Increment the value of a variable}}
{{info} {Interpreter Routines} {Return information about the state of the Tcl interpreter}}
{{interp} {Interpreter Routines} {Create and manipulate Tcl interpreters}}
{{join} {List Handling} {Create a string by joining together list elements}}
{{lappend} {Variables and Procedures} {Append list elements onto a variable}}
{{lindex} {List Handling} {Retrieve an element from a list}}
{{linsert} {List Handling} {Insert elements into a list}}
{{list} {List Handling} {Create a list}}
{{llength} {List Handling} {Count the number of elements in a list}}
{{load} {Packages and Source files} {Load machine code and initialize new commands.}}
{{loadTk} {Packages and Source files} {Load Tk into a safe interpreter.}}
{{lrange} {List Handling} {Return one or more adjacent elements from a list}}
{{lreplace} {List Handling} {Replace elements in a list with new elements}}
{{lsearch} {List Handling} {See if a list contains a particular element}}
{{lset} {Variables and Procedures} {Change an element in a list}}
{{lsort} {List Handling} {Sort the elements of a list}}
{{memory} {Interpreter Routines} {Control Tcl memory debugging capabilities.}}
{{msgcat} {Library Procedures} {Tcl message catalog}}
{{namespace} {Variables and Procedures} {create and manipulate contexts for commands and variables}}
{{open} {Output} {Open a file-based or command pipeline channel}}
{{package} {Packages and Source files} {Facilities for package loading and version control}}
{{pid} {System Related} {Retrieve process id(s)}}
{{pkg::create} {Packages and Source files} {Construct an appropriate \fBpackage ifneeded\fR}}
{{pkg_mkIndex} {Packages and Source files} {Build an index for automatic loading of packages}}
{{proc} {Variables and Procedures} {Create a Tcl procedure}}
{{puts} {Output} {Write to a channel}}
{{pwd} {System Related} {Return the current working directory}}
{{re_syntax} {String Handling} {Syntax of Tcl regular expressions.}}
{{read} {Output} {Read from a channel}}
{{regexp} {String Handling} {Match a regular expression against a string}}
{{registry} {Platform-specific} {Manipulate the Windows registry}}
{{regsub} {String Handling} {Perform substitutions based on regular expression pattern matching}}
{{rename} {Variables and Procedures} {Rename or delete a command}}
{{resource} {Platform-specific} {Manipulate Macintosh resources}}
{{return} {Control Constructs} {Return from a procedure}}
{{scan} {String Handling} {Parse string using conversion specifiers in the style of sscanf}}
{{seek} {Output} {Change the access position for an open channel}}
{{set} {Variables and Procedures} {Read and write variables}}
{{socket} {Output} {Open a TCP network connection}}
{{source} {Packages and Source files} {Evaluate a file or resource as a Tcl script}}
{{split} {List Handling} {Split a string into a proper Tcl list}}
{{string} {String Handling} {Manipulate strings}}
{{subst} {String Handling} {Perform backslash, command, and variable substitutions}}
{{switch} {Control Constructs} {Evaluate one of several scripts, depending on a given value}}
{{tell} {Output} {Return current access position for an open channel}}
{{time} {System Related} {Time the execution of a script}}
{{trace} {Variables and Procedures} {Monitor variable accesses, command usages and command executions}}
{{unknown} {Interpreter Routines} {Handle attempts to use non-existent commands}}
{{unset} {Variables and Procedures} {Delete variables}}
{{update} {Control Constructs} {Process pending events and idle callbacks}}
{{uplevel} {Control Constructs} {Execute a script in a different stack frame}}
{{upvar} {Variables and Procedures} {Create link to variable in a different stack frame}}
{{variable} {Variables and Procedures} {create and initialize a namespace variable}}
{{vwait} {Control Constructs} {Process events until a variable is written}}
{{while} {Control Constructs} {Execute script repeatedly as long as a condition is met}}
}
foreach row $data \
{
foreach {c1 c2 c3} $row \
{
foreach i {1 2 3} \
{ .ml.f.l$i insert end [set c$i] }
}
}See also edit
- http://www.geocities.com/pa_mcclamrock/wishlist-0.2.2.tar.gz
(broken) - A minimal minimal multi listbox widget
D. McC See also WISH List 0.2.2: http://www.geocities.com/pa_mcclamrock/wishlist-0.2.2.tar.gz
(broken)PWQ: Taking a devils advocate approach see A minimal minimal multi listbox widget
Zipguy 2013-07-03 - You can find out my email address by clicking on Zipguy.ulis was a great guy who passed on. So, I fixed the screenshot above (which is from my site).Also, I made the two files together, which did not work as separate files (they would have needed pkgindex.tcl and provide statement within the multilist.tcl), into one file.Then I converted it to an SDX file, using ezsdx, and provided it at demo_multil_simple.kit
. It is around 4.4k vs 12k which makes it a lot smaller. You could use SDX, or ezsdx, to unwrap it. If you're not concerned about size, then you could also download it at demo_multil_simple.exe
(which is around 1.3M, but you can't see what's inside of it).It is rather simplistic, hard coded for only for 3 columns, without sorting options, but it does work well. And it does have a rather interesting resizing columns facility, built in to it.
