Displaying tables

Arjen Markus The following script is a result of suggestions by Andreas Kupries and Jeff Hobbs: how to display tabular data.

The ::struct::matrix module in Tcllib makes it very easy to manage data in the form of a table. The Tktable extension is capable of showing data in the form of a table, but it uses a different method for storing the data. Luckily, the ::struct::matrix module has a command to link the matrix to an array (and vice versa).

Note: from my (very) limited experience I conclude that things are not quite perfect yet. But, with just twenty lines of code, one can achieve a beautiful demonstration of the ideas!


Some imperfections:

  • The order for creating the array and linking it to a matrix is fixed.
  • Updates to the matrix (via the matrix's methods) are not always reflected in the table. Changes in the table (via the widget) are.

   # Demonstrate the combination of ::struct::matrix and Tktable
   #
   package require struct
   package require Tktable

   #
   # Create a matrix called "simpleTable"
   #
   ::struct::matrix simpleTable

   #
   # The matrix must have some columns before it will accept rows
   #
   simpleTable add columns 4
   simpleTable add row {A1 A2 A3 A4}
   simpleTable add row {B1 B2 B3 B4}
   simpleTable add row {C1 C2 C3 C4}

   #
   # A small glitch in the default formatter makes it necessary to
   # force a new line
   #
   simpleTable format 2chan
   puts ""

   #
   # Note: the array table_data must be defined before the link
   # with the matrix!
   #
   table .table -variable table_data -width 4 -height 3
   pack .table -fill both

   simpleTable link -transpose table_data

   simpleTable set cell 2 2 XX

   puts "Elements: [array get table_data]"

RS likes to depend on nothing (and has no Tcllib or Tktable on the iPaq, for instance). Here's a minimal solution to display a table (list of lists) in a grid of labels:

 package require Tk
 proc table {w content args} {
     frame $w -bg black
     set r 0
     foreach row $content {
         set fields {}
         set c 0
         foreach col $row {
             lappend fields [label $w.$r/$c -text $col]
             incr c
         }
         eval grid $fields -sticky news -padx 1 -pady 1
         incr r
     }
     set w
 }

#--- Test:
 table .t {
    {Row Head1 Head2}
    {1   foo   42}
    {2   bar   1234}
    {3   grill testing}
 }
 pack .t

#--- Changing the contents, given row and column number:
 after 2000 .t.3/2 config -text Coucou

Only after writing this, and reading the printout over a cup of coffee, I noticed that I had evidently reused the pattern of A little calculator... The more I code, the harder is code re-use, because it's hard to remember where it was, and what it was called... somehow, idea reuse is simpler, and more fun, too.


LV Techniques for making code reuse easier


WikiDbImage tabletext.jpg

RS 2006-04-07 - Here's an example of embedding such a table in a text widget (I gave the labels the additional options -anchor w -bg white):

 pack [text .t]
 .t insert end "Headline for a little table\n\n"
 set content {
     {First Last}
     {John Brown}
     {Mary Smith}
     {Konstantinos Papadopoulos}
 }
 .t window create end -window [table .t.x $content]
 .t insert end \n\n
 .t insert end "More plain body text continues here..."

AM Alternatively, you can of course just Draw a table on a canvas, if you merely want to show it (and print it ...)


KPV See also Simple Tktable.