Version 4 of Virtual grid widget

Updated 2004-02-17 09:09:31

17feb04 jcw - The following code is a quick experiment to explore the use of a virtual grid to show potentially huge amounts of data without having to copy them into the GUI. This "data aware widget" approach would work well with databases (and an upcoming package called Ratcl).

The key idea is to maintain a grid of widgets which is twice the number of widgets displayed in both dimensions. Then, scrolling can reassign the "allocation" of each widget to the cell it currently represents. IOW, widgets stay on a canvas, caching the ones which are visible (plus a few more), and a window moves around, creating the illusion of moving over a huge virtual grid of widgets. By not creating widgets all the time, and by not even moving them around on the canvas, we get the benfit of Tk's double-buffering to cache visual detail and reduce the number of callbacks. In the image below, the arrows indicate reassignment of widgets, not movement or copying:

http://www.equi4.com/images/virtual-scroll.png

And here's code which places widgets on a canvas. It does not scroll yet, it's not more than a very first start at creating such a widget:

    package require Tk

    proc celldef {w px py} {
      label $w -anchor w \
        -text "($px,$py) [string repeat . [expr {$px+$py}]]"
    }

    proc ginit {w rows cols} {
      global cells$w
      for {set y 0} {$y < $rows} {incr y} {
        set cmd grid
        for {set x 0} {$x < $cols} {incr x} {
          set cell $w.$x,$y
          celldef $cell $x $y
          lappend cmd $cell
          set cells${w}($x,$y) -1,-1
        }
        eval [lappend cmd -sticky nsew -row $y]
        grid rowconfig $w $y -uniform a
      }
      for {set x 0} {$x < $cols} {incr x} {
        grid columnconfig $w $x -uniform a
      }
    }

    proc gconf {w} {
      $w.c configure -scrollregion [grid bbox $w.c.f]
    }

    proc gview {w} {
      frame $w
      scrollbar $w.h -command "$w.c xview" -orient horiz
      scrollbar $w.v -command "$w.c yview"
      canvas $w.c -xscrollcommand "$w.h set" -yscrollcommand "$w.v set"
      pack $w -expand 1 -fill both
      grid rowconfig $w 0 -weight 1 -minsize 0
      grid columnconfig $w 0 -weight 1 -minsize 0
      grid $w.c -row 0 -column 0 -sticky news
      grid $w.v -row 0 -column 1 -sticky news
      grid $w.h -row 1 -column 0 -sticky news
      bind $w <Configure> "gconf $w"
      frame $w.c.f
      $w.c create window 0 0 -window $w.c.f -anchor nw
      return $w.c.f
    }

    ginit [gview .f] 10 6

Feel free to use, re-use, alter, extend, and/or comment as you like.


D. McC: How would this compare with a set of multi-scrolling listboxes using the -listvariable option, which could be vertically scrolled and horizontally gridded or un-gridded as needed? More, less, or equally efficient?