Version 7 of Simple Tktable

Updated 2006-03-07 20:19:20

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 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.


 ##+##########################################################################
 #
 # 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: don't allow any whitespace
 proc vcmd {row col val} {
    if {$col < 2} { 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

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?


[ Category GUI | Category Widget ]