Donal Fellows (originally in the Bag of Tk algorithms)
# Make our contents and a list of frame names... for {set i 0} {$i<15} {incr i} { set w .lb$i frame $w listbox $w.lb -xscrollcommand "$w.x set" -yscrollcommand "$w.y set" scrollbar $w.x -command "$w.lb xview" -takefocus 0 -width 10 \ -orient horizontal scrollbar $w.y -command "$w.lb yview" -takefocus 0 -width 10 $w.lb insert end "LISTBOX $i" "A: This is listbox $i" \ "B: This is listbox $i" "C: This is listbox $i" \ "D: This is listbox $i" "E: This is listbox $i" grid $w.lb $w.y -sticky nsew grid $w.x -sticky ew grid columnconfigure $w 0 -weight 1 grid rowconfigure $w 0 -weight 1 lappend lbs $w } # How many frames to show at once? set width 4 # Our primary scrollbar scrollbar .sb -command "doScroll" -orient horizontal -width 20 # And set up the static parts of the geometry manager grid .sb -row 1 -columnspan $width -sticky ew for {set i 0} {$i<$width} {incr i} { grid columnconfigure . $i -weight 1 after idle grid columnconfigure . $i -minsize \[winfo reqwidth .lb0] } grid rowconfigure . 0 -weight 1 after idle grid rowconfigure . 0 -minsize \[winfo reqheight .lb0] # We start at the left... set pos 0 proc reconf {} { global pos lbs width .sb set [expr {double($pos)/([llength $lbs])}] \ [expr {double($pos+$width)/([llength $lbs])}] eval grid forget $lbs eval grid [lrange $lbs $pos [expr {$pos+$width-1}]] -row 0 } proc Xscroll {n units} { global pos width switch $units { units {incr pos $n} pages {incr pos [expr {$n*$width}]} } } proc Xmoveto {fraction} { global pos lbs set pos [expr {int([llength $lbs]*$fraction)}] } proc doScroll {args} { global pos lbs width set oldpos $pos set len [expr {[llength $lbs]-$width}] eval X$args if {$pos<0} {set pos 0} elseif {$pos>$len} {set pos $len} if {$pos != $oldpos} {reconf} } # Set up the scrollbar and frames... reconf
Also see Virtual Scrolling for another solution that does not use text or canvas.