Updated 2014-12-30 07:26:22 by OK

Keith Vetter 2005-10-27 : A recent project of mine required using Tktable for three tables. One of the tables was complex, with scrolling, spans and conditional formatting, but the other two tables were just simple forms with a title row, some readonly columns and the rest were editable cells.

I found for those simple tables that Tktable was a bad fit. The biggest problem was that the users expected the editable cells to act like entry widgets but they don't: you can't select with the mouse, arrow keys take you out of the cell, and tabbing takes you out of the table.

So instead I cobbled together what I call a simpleTable megawidget. It's a grid of entry and label widgets tied together with a shared -variable array. It has a simple subset of Tktable's options, including -variable, -rows, -cols, -titlerows, -titlecols, -readonlyrows, -readonlycols, and -vcmd.

Fairly simple code--if you take out the error checking code, it's not much longer than the code to create a tktable with all its options and necessary tag configures.

uniquename 2013aug18

For the reader who does not have time/facilities/whatever to setup the code below and execute it, here is an image of the demo table that the code below creates.

I had to comment the 'return' statement at the bottom of the code --- otherwise the GUI was not displayed. I also removed the '-padx' and '-pady' options from the 'pack .t' statement near the bottom of the code --- in order to reduce the size of the image captured (and thus reduce the disk space it requires on the disk drives of the server of this wiki).

That is all that I changed --- other than adding the following statement at the top of the code.
   #!/usr/bin/wish

 ##+##########################################################################
 #
 # simpleTable.tcl -- replacement of tktable for simple tables
 # by Keith Vetter, October 2005
 #
 proc simpleTable {pathName args} {
    set legal {-rows -cols -titlerows -titlecols -vcmd
        -readonlyrows -readonlycols -variable}
    array set A {-rows 5 -cols 5 -titlerows 0 -titlecols 0
                     -readonlyrows {} -readonlycols {}}
 
    if {[llength $args] == 0} {
        error "usage: simpleTable pathName -variable varName ?options...?"
    }
 
    set idx -1
    foreach {opt value} $args {
        if {[lsearch $legal $opt] == -1} {
            error "unknown option \042$opt\042"
        }
        if {[incr idx 2] >= [llength $args]} {
            error "value for \042$opt\042 missing"
        }
        set A($opt) $value
    }
    if {! [info exists A(-variable)]} {
        error "missing the \042-variable\042 option"
    }
 
    # Now build our table
    destroy $pathName
    frame $pathName
    for {set r 0} {$r < $A(-rows)} {incr r} {
        for {set c 0} {$c < $A(-cols)} {incr c} {
            set w "$pathName.r${r},$c"
            if {$r < $A(-titlerows) || $c < $A(-titlecols)} {
                if { $::tcl_platform(platform) eq "windows" } {
                    set bg SystemDisabledText 
                } else {
                    set bg darkgrey
                }
                label $w  -textvariable $A(-variable)\($r,$c\) \
                    -relief flat -bg $bg -fg white
            } elseif {[lsearch $A(-readonlyrows) $r] != -1 || \
                      [lsearch $A(-readonlycols) $c] != -1} {
                label $w -textvariable $A(-variable)\($r,$c\) \
                    -relief sunken -bd 2
                $w config -font [lindex [$w config -font] 3]
            } else {
                entry $w -textvariable $A(-variable)\($r,$c\) \
                    -relief sunken -bd 2 -justify center -width 9
                if {[info exists A(-vcmd)]} {
                    $w config -validate key \
                        -vcmd [list $A(-vcmd) $r $c %P]
                }
            }
            grid $pathName.r${r},$c -row $r -column $c -sticky ew
        }
    }
 }
 
 ################################################################
 #
 # Demo code
 #
 package require Tk

 # Fill in our table variable
 set rows 10
 unset -nocomplain table
 array set table {
    0,0 Position 0,1 "Last Name" 0,2 "First Name" 0,3 "Home Runs"
 }
 for {set row 1} {$row < $rows} {incr row} {
    set table($row,0) [expr {$row == 1 ? "1st" :
                             $row == 2 ? "2nd" :
                             $row == 3 ? "3rd" : "${row}th"}]
    set table($row,1) ""
    set table($row,2) ""
 }
 set table(1,1) "Aaron"    ; set table(1,2) "Hank"    ; set table(1,3) 755
 set table(2,1) "Ruth"     ; set table(2,2) "Babe"    ; set table(2,3) 714
 set table(3,1) "Bonds"    ; set table(3,2) "Barry "  ; set table(3,3) 703
 set table(4,1) "Mays"     ; set table(4,2) "Willie " ; set table(4,3) 660
 set table(5,1) "Robinson" ; set table(5,2) "Frank "  ; set table(5,3) 586
 set table(6,1) "McGwire"  ; set table(6,2) "Mark "   ; set table(6,3) 583
 set table(7,1) "Sosa"     ; set table(7,2) "Sammy "  ; set table(7,3) 574
 
 
 # validate command for our table's last column: only allow valid numbers
 proc vcmd {row col val} {
    if {$col < 3} { return 1 }
    if {[regexp {\s} $val]} { return 0 }
    return [string is double $val]
 }
 
 simpleTable .t -variable table -rows $rows -cols 4 \
    -titlerows 1 -readonlycols 0 -vcmd vcmd
 pack .t -padx 1i -pady .5i
 return

EKB As a less streamlined approach, I set up a TkTable widget to pop up an entry widget in the active cell on either a dbl-click event or a keyboard shortcut. The code is here: Inserting an Entry Widget in TkTable

HJG I don't understand the intention of proc vcmd: in the "First Name"-column, only numbers are allowed ?

LV I agree. I just tried running this on a Windows XP SP2 system using Tcl 8.4.6. What I got was the first name column permitting me to put anything, including white space, the last name column not permitting me to make any changes, and the numeric field allowing numbers. Was that the intent?

KPV Oops, a mis-copy. It should be that the last column only allows valid numbers. Fixed the code so that vcmd only does it check when the column is the last column.

[ICU] - 2010-03-01 02:11:56

Any idea how you could add a scrollbar to this?

Martyn Smith Take a look at BWidget ScollableFrame then use the frame as the base for this widget.

[ICU] - 2010-03-01 07:18:44

I was able to make it work. Still need to figure out how to make the frame fill both vertical and horizontal. Anyway thanks!

[Jan] - 2013-02-22 15:48:57i am trying to add scrollbar as below to the simpletable but getting an error. The scrollbar appears but when the arrow is clicked an error comes. I am new to this scripting language.. Can you please tell how to make it work...
simpleTable .t -variable table -yscrollcommand ".sr set" , 
scrollbar .sr -command ".t yview"   ,
pack .sr .t -padx 1i -pady .5i

RLE (2013-02-23): It would be most helpful to know what error you receive.

My best guess, simpleTable appears to not allow for scrollbars.

[PG] - 2013-05-06 14:17:34

You can use a canvas for example and you also need to set a view for the scrollbar to work. see the wiki on the scrollbar

[OK] - 2014-12-30 07:26:22

So, did anybody try to add scrollbar to the table? For the canvas-based approach one needs to specify scroll-region size, and it's not clear (to me) how to determine it safely.