Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

using TK Table 2

Status
Not open for further replies.

Bong

Programmer
Dec 22, 1999
2,063
US
I've been fooling around with the TkTable widget/dll that came with the 8.3.4.2 download. I have a suspicion that it could be deucedly useful but so far I'm just amusing myself. In case there are others like me I thought I'd include what I've done so far. In particular, I use a lot of ASCII "databases" that are really comma separated value files. I don't want to use a spreadsheet to look at them since that takes longer and seems inelegant. So, I have a routine to populate a table with the contents of the database (or, really, any comma delimited file) and to edit the table (and hence the matrix) and save the result:

#set default filename
set filename tlmdb.csv
#
load "c:/program files/tcl/lib/tktable2.7/tktable.dll"
wm title . "CSV View/Edit"
wm deiconify .
frame .top -borderwidth 2
pack .top -side top
set w .top
label $w.lb -text "CSV file name: "
entry $w.en -textvariable filename -width 42
button $w.bu -text readCSV -command fillTbl
bind $w.en <Return> fillTbl
bind . <Escape> exit
pack $w.lb $w.en -side left
pack $w.bu -side left -padx 12
proc fillTbl {} {
destroy .t .yscr .xscr .f
frame .f -borderwidth 2 -relief groove
pack .f -side bottom
set w .f
button $w.r -text Add_row -command {.t insert rows end 1}
button $w.d -text Del_row -command {.t delete rows [.t index active row] 1}
button $w.s -text Save -command saveM
pack $w.r $w.d $w.s -side left -padx 3 -pady 3
table .t -yscrollcommand &quot;.yscr set&quot; -xscrollcommand &quot;.xscr set&quot;
scrollbar .yscr -command &quot;.t yview&quot;
scrollbar .xscr -command &quot;.t xview&quot; -orient horizontal
pack .yscr -side right -fill y
pack .t -side top
pack .xscr -side top -fill x
.t configure -variable m -bg white -width 12 -height 12
set fid [open $::filename r]
set flst [split [read $fid] \n]
close $fid
set nrows [llength $flst]
.t configure -rows $nrows
.t configure -cols [llength [split [lindex $flst 0] ,]]
catch [array unset ::m] rtn
for {set i 0} {$i<$nrows} {incr i} {
set linen [lindex $flst $i]
set llst [split $linen ,]
foreach elm $llst {
set j [lsearch $llst $elm]
set ::m($i,$j) $elm
}
}
}
proc saveM {} {
global m filename
set fid [open $filename w]
set nrows [.t cget -rows]
set ncols [.t cget -cols]
for {set i 0} {$i<$nrows} {incr i} {
set rwlst &quot;&quot;
for {set j 0} {$j<$ncols} {incr j} {
if [catch {lappend rwlst $m($i,$j)} rtn] {lappend rwlst &quot; &quot;}
}
set ostring [join $rwlst ,]
puts $fid $ostring
}
close $fid
}


As I said, this is really self-amusement so far but I have a feeling it will come in handy soon. Bob Rashkin
rrashkin@csc.com
 
By the way, if you're using comma-separated value (CSV) data in your Tcl applications, you might like to know that the Standard Tcl Library, tcllib, now has an extension for manipulating CSV data, csv. The csv package supports both parsing and creating CSV data. It also supports delimiter characters other than &quot;,&quot;, though that's the default. It also handles cases where the CSV data has embedded delimiter characters in the data, such as:

Ken,Jones,&quot;President, CEO, and Head Honcho&quot;

You can find out more information about the csv package from the Tcl'ers Wiki ( on the page You can download the latest version of tcllib (and thus csv) from SourceForge at
For what you're doing, Bong, you might be particularly interested in another package provided by tcllib, struct, which includes a matrix implementation that works very well with TkTable and the csv package. Just make sure you download the latest version of tcllib (1.2 or later) to get all the latest nifty features.

Without getting into all the gory details, you could replace a big chunk of your code for reading and writing your CSV data with these packages. For example:

Code:
package require Tktable
package require csv
package require struct

# We're ignoring a lot of your widget creation,
# packing, etc. to concentrate just on populating
# the table with your data...

# Create the table and link it to the
# global &quot;vals&quot; array

table .t -variable vals
pack .t -expand yes -fill both

# Create a matrix structure named &quot;values&quot;

::struct::matrix values

# Open our data file

set fid [open $file r]

# Magically read and parse the CSV data,
# storing the results in our matrix

::csv::read2matrix $fid values &quot;,&quot; auto
close $fid

# Link our matrix to our global &quot;vals&quot; array.
# This automagically displays the data in our
# table, and then keeps our table and our matrix
# data structure synchronized.

values link -transpose vals

# ...

# Later, when you want to write out the updated
# CSV data from your table, just do this...

set fid [open $file w]
::csv::writematrix values $fid
close $fid
- Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
By the way, I didn't mean to minimize what you'd accomplished, Bong. It is clever, and quite useful. I hadn't thought of putting together all of the pieces in quite that way before. My original intention was to show how by using Tcl's csv package, you could eliminate most of your parsing code. Then, once I started investigating csv in greater depth, I saw how it had been extended to make use of the struct/matrix package. And when I investigated the matrix package further, I saw how it had the neat-o way of linking to a global array in just the right way to work with TkTable. Which dovetailed in wonderfully with exactly what you were doing.

So, your original idea was quite clever, but implementing it with these other packages makes it slicker than... well, it makes it really slick. :) - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Avia (Ken),

I actually tried using the csv::read2matrix but it returned an error (&quot;m&quot; is not a valid command) and the reading a csv file part is so easy that I didn't pursue it. Bob Rashkin
rrashkin@csc.com
 
It sounds as though you didn't create your matrix before calling ::csv::read2matrix, but that's just a thought. I also had a few problems using an older version of the tcllib packages, but those cleared up when I downloaded the latest version of tcllib (1.2). - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Avia,

I looked at your example and realized that what I had NOT done was to initialize the matrix (&quot;values&quot;) in your example. That's why I got the error. I like your use of the struct and csv packages. I'm just getting used to using the tcllib stuff.

Why do you use both &quot;values&quot; and &quot;vals&quot;? And, what is this &quot;arrayName link ...&quot; command? I can't find any reference to in the help file. Bob Rashkin
rrashkin@csc.com
 
The way that tcllib's struct package works is that when you create a structure like a matrix, it creates not only a data structure object, but also an associated Tcl command with the name you provide. So,

Code:
::struct::matrix values

creates a command whose name is values. You then use this command to manipulate the data structure. The package hides the implementation details of how the data is actually managed internally. This is also analogous to the way widgets work in Tk. When you create a button:

Code:
button .b

Tk creates a command called .b for you to use when manipulating the widget, as in:

Code:
.b configure -text &quot;Click me&quot;

As for why I used both &quot;vals&quot; and &quot;values,&quot; it wasn't strictly necessary. But I wanted to clearly distinguish between the global array variable, vals, and the matrix object, values. Giving them both the same name would make it seem as though we were passing around a single data structure that could morph between array and matrix representations as needed, which is kinda cool, but I wanted to emphasize the distinction between the array variable and the matrix object in this case.

Which actually brings me to your last question. The &quot;link&quot; operation applies to matrix objects. It's described in the matrix reference page, which you can read at So:

Code:
values link -transpose vals

executed the values command corresponding to my &quot;values&quot; matrix object, telling it to run its &quot;link&quot; operation. Its function is to link a global array variable to the matrix object. After doing so, changes to the matrix object, values, are automatically reflected in the array variable, vals, and vice versa. The -transpose option is needed because the matrix would usually map its contents into the array using indices of the form &quot;column,row&quot;, but the TkTable widget needs an array with indices of the form &quot;row,column&quot;. The -transpose option causes the matrix object to map its values using the &quot;row,column&quot; index format compatible with TkTable. - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
You're right. This is way slick!
So, the &quot;link&quot; command you performed on values and vals is similar to &quot;upvar&quot;? Bob Rashkin
rrashkin@csc.com
 
Well, not quite the same as upvar. More like the -textvariable and -listvariable options of various widgets.

However, now that I've started playing around with the matrix's link operation, I'm finding a few bugs. I think this is some recent code that hasn't been excercised enough. One major problem I'm seeing is that after linking, changes to the matrix object aren't being propagated correctly to the linked array. I need to file a bug report on that. I also noticed that if I've got the same array variable liked to a TkTable, inserting rows or columns isn't propagated to the linked matrix object. So, another bug report for that.

So, as slick as it seems as first, it isn't quite ready for prime time. *sigh* Give it another revision and the matrix linking features should be okay for production use. - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
OK. I guess I still think TkTable is potentially pretty useful.

I also still think the &quot;link&quot; function (when it works) is similar to &quot;upvar&quot; since in links the variables in different spaces (unlike -textvariable).

And let me say that I have found this exchange to be thouroughly enjoyable. I hope to see more of its like in this forum. Bob Rashkin
rrashkin@csc.com
 
I agree, TkTable is very useful. It's also been around for a while, and so is a pretty solid package. Most of the tcllib packages are well-tested, too. We just happened to hit a relatively new feature (matrix linking) that didn't get tested quite as much as it should have.

But speaking of those bugs, one of them that I reported has already been fixed, and the patch is in the tcllib CVS head. We've also identified the cause of the second bug, and I suspect that it'll get patched and committed to CVS by early next week. Once that's done, our little scheme of linking a matrix and a TkTable through a common array variable should work fine.

I appreciate the opportunity to bounce ideas around like this as well. I'd not spent much time poking around the csv and struct modules of tcllib; I just knew of their basic functionality. This gave me a good excuse to investigate them at greater length and learn about some of their neat, time-saving features. So, thanks again for bringing up this topic! - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top