Tablelist , by Csaba Nemethi, is a multi-column listbox and treeview widget for Tk.


latest release
release time
Csaba Nemethi


"... The only other widget that makes frequent appearances in my code is Csaba Nemethi's Tablelist - which is a fantastic widget in its own right.".

APN: Having used it in WITS, I would like to second that sentiment. An absolute must-have for any Tk programmer's toolbox.

See also


Tablelist is also a general utility module for other megawidgets like tablelist. This widget allows each column to be dynamically sized and has several alignments. It supports multi-line cells and interactive cell editing. It supports multi-column sorting. It supports a variety of listbox like commands. Can generate line numbers. Includes Tablelist_tile for a themed version of the widget. Supports (Tile based) multi-entry widgets as edit windows. Supports cell- and column label-specific balloon help. It comes with bindings so that it acts like a listbox.

You can also find Tablelist in tklib. You will have to read the docs at the web site mentioned above, however, as none currently are bundled with tklib.


Other screenshots are here .

Jeff Smith 2024-06-10 : Below is an online demo using CloudTk. This demo runs "tablelist" in an Alpine Linux Docker Container. It is a 29.2MB image which is made up of Alpine Linux + tclkit + tablelist7.2.kit + libx11 + libxft + fontconfig + ttf-linux-libertine. It is run under a user account in the Container. The Container is restrictive with permissions for "Other" removed for "execute" and "read" for certain directories.

By clicking on the "V" in the upper left corner you can access other demos.

Basic usage

package require Tk
package require tablelist 
tablelist::tablelist .t -columns {0 "First Column" 0 "Another column"} -stretch all -background white
pack .t -fill both -expand 1 -side top
.t insert end [list "first row" "another value"]
.t insert end [list "another row" "bla bla"]

EKB: When testing this script, make sure you don't save this script with the filename "tablelist.tcl", like I did. It will collide with the class name of the tablelist widget, which is "Tablelist". (Thanks to Csaba for helping me out with this.)

Csaba Nemethi: There is an important rule which is probably not as widely known as it should be:

Never, never name a stand-alone Tcl/Tk script for Windows "listbox.tcl", "Listbox.tcl", "entry.tcl", "tablelist.tcl", etc. By doing so, Tk will create a main window of the class "Listbox", "Entry", "Tablelist", etc., and one or two mouseclicks anywhere on the application window, outside a listbox, entry, or tablelist widget contained in it, will generate a strange error message. This is because the binding scripts for <Button-1>, <FocusIn>, or whatever associated with that widget class expect a listbox, entry, or tablelist widget, but they get invoked for a wish main window instead.

RLH: 2005-11-02: I get the following error when running the above:

invalid command name "tablelist::tablelist"
   while executing
"tablelist::tablelist .t -columns {0 "First Column" 0 "Another column"} -stretch all -background white"
   (file "tabletest.tcl" line 3)

Csaba Nemethi 2005-11-21: This error is raised when using the latest ActiveTcl version, including tklib0.3, which in turn contains Tablelist 4.2. Unfortunately, the Tablelist tclIndex file is missing in tklib0.3, and this is the reason for the above error message. The recommended way to get rid of this problem is to use the latest Tablelist release from instead of the one contained in tklib. Since both have the version number 4.2 (this is bad), you will have to look at the value of the variable tablelist::library to check the location of the package being used.

This code will give this picture (Linux with afterstep):

Beyond this point, you can do many many thing with tablelist like sorting, cell editing, hiding columns, moving columns and rows interactively, display content too long for a cell with '...' or another snipstring, color individual cells/rows/columns, and of course configure the widget in many different ways.

Tablelist is a real powerhouse!

IDG 2011-09-07: Trouble with 6.0b1 and tablelist 5.3

On Linux I see:

~/misc> wish
% info patch
% package require tablelist
couldn't recognize image data

~/misc> /usr/bin/wish8.4
% info patch
% package require tablelist

~/misc> wish
% info patch
% package require -exact tablelist 4.5

Does anyone know what's happening?

Csaba Nemethi 2011-09-07: The reason is that Tablelist assumes the presence of PNG support in Tk 8.6. When doing so, it only checks the version number, not the patch level. Actually, the PNG support was introduced in Tk 8.6b1.1. Your Tcl/Tk distribution has the patch level 8.6b1, which still misses PNG support and thus fails to recognize some image data in PNG format. The easiest way to solve the problem is to install a more recent Tcl/Tk release (e.g., ActiveTcl is based on Tcl/Tk 8.6b2).

Using Tablelist as a tree widget

Recent releases of Tablelist (since 5.0) support the display of data as a tree widget, with one or more columns. Example:

package require Tk
package require tablelist
tablelist::tablelist .t -columns {0 "First Column" 0 "Another column"} -stretch all -background white -stretch all 
pack .t -fill both -expand yes
set data "tree"
.t insertchildlist root end $data
.t collapse 0
set childlist1 [list {row 1} {row 2} {another row}]
.t insertchildlist 0 end $childlist1

This will give this picture:

LV Does anyone have a useful example showing tablelist and -listvariable?

DRH How can the tree's hierarchy be retrieved (and saved to file) once the data has been entered dynamically? I could not find this in the documentation or demos.

Csaba Nemethi 2016-01-02: For a given node index, you can use the childcount and childkeys subcommands to get the number of children and the list of their full keys, respectively. Start with the node index "root", descend to its children (i.e. the top-level items), then to its grandchildren, and so on.

EMJ 2017-01-28: So now I am trying to work out how to use tablelist-as-tree as the editwindow for another tablelist, since the full dropdown list would be ridiculously long but there is a hierarchy which would make choice much easier for the user.

Comparison of tablelist and Tktable

tablelist may be compared with tktable, but there are differences. Fundamentally, Tablelist is row based, because it is a listbox, just with multiple columns. While you can access single cells, it wasn't made for this. Tktable was made for single cells that form a table. Tktable can have an array variable linked to the values in the cells, while tablelist has a listvariable that reflects the rows.

Then, tktable is written in C and is thus very quick and can handle lots of data, while there will be a slowdown in tablelist once you handle more than a few thousand rows. Some other differences are:

  • tktable can have non-scrollable rows/columns
  • tktable has tags (like in canvas and text)
  • tktable can (interactively) resize row heights
  • tktable has input validation
  • tktable can have non-contiguous cell selections
  • ----
  • tablelist has built-in sorting of rows
  • tablelist is very easy to use and can often be used as an in-place replacement for Tk's listbox
  • tablelist has seperate commands that can evaluated during start and end of cell edition

RLH: There was a discussion here on the comparison: [L1 ]

JH 2006-06-15: In creating a new app where I needed a multi-column listbox, I gave tablelist, tktable and treectrl all a test run. With a working set of ~6000 rows by 7 column (>40K cell elements). Assuming a base size of 20MB for my app to load this data, using snidgets wrapping each of the types, the treectrl grew by 40MB (i.e. to 60MB total), tablelist grew by 20MB and tktable grew by 10MB. tktable was the fastest (about 3 sec load), then treectrl (~5sec), followed by tabelist (~8sec). Usage after load was fairly similar. In the end, for my needs based on features, I chose treectrl. Thought tablelist was close, I needed better performance.

MSH 2006-06-16: It may also be a question of look and feel. I use both treectrl and tablelist; the new tablelist (>4.0) integrates much easier with tile and looks a lot better; tablelist is also a lot easier to use by following the logic (no elements, or styles, associated list variable ...) of established (i.e., listbox) standard widgets.

Csaba Nemethi 2006-06-16: Just for the sake of completeness: tablelist widgets have a significantly increased performance when using dynamic-width columns. It would be interesting to know whether this was the case in the test mentioned above; if not, the load time corresponding to a tablelist widget with dynamic-width columns would make the comparison more complete. Another way to speed up the insertion of items is to use the insertlist subcommand (or the -listvariable option) rather than inserting them one by one via insert.

WJP 2008-01-21: The speedup from using insertlist rather than multiple calls to insert is substantial. I just tried this with my UnicodeDataBrowser, which loads 17,000 items each of 10 columns. The insertion time dropped to 40% of the previous value.

JH 2006-06-18: I used the -listvariable method for insertion (repeatedly appending to the end, with some lsets as well). I'm not sure what you mean by dynamic-columns ... there were 7 fixed columns of fixed width. BTW, I was also using the tile-based tablelist. I had no problem with appearance, just speed. It was also the speed of a full table sort (more than twice as long as treectrl to sort the 6K rows).

Csaba Nemethi 2006-06-18: Dynamic-width columns automatically adjust the space needed to hold all their elements, including the header. They are created by specifying the width 0 at the corresponding positions of the list given as the value of the -columns option. Both the insertion and the sorting of the items are a lot faster when using dynamic-width columns, because there is no need to trim the elements that don't fit into their cells.

Comparison of tablelist and ttk::treeview

AMG: How does tablelist compare to treeview?

Add-ons for tablelist

ABU 2005-11-03:

ColumnCtrl is a small add-on for the tablelist package.

Columnctrl provides an interactive control of tablelist's columns.

With this control, user can show/hide columns, as well as change columns order.

Here are two screenshots:

A classic tablelist widget with an 'attached' column-control button:

Here is the extended control panel:

Columnctrl comes with Multi-lingual support, providing messages based on the current-locale. (currently only "english", "italian" and "german").

Columnctrl supports the tile theme-engine:

  • If the 'attached' tablelist is tile-based, then also the columnctrl's user-interface will be tile-based.

ABU 2005-11-21:

ColumnCtrl ver. 1.1.1 released and above links updated.

See also Mac style tables with tablelist for another approach to this column visibility management.


(rwm) Warning: The version included with kitten is an old 2.7. I'm not sure why...

LV: Does kitten continue to get updates? I suspect not, but do not know for certain.

crv: I like the auto-sort capability but how do you disable it? I am developing an application whereby an accidental sort will foul up things.

slebetman: No need to disable it. By default it is not on. To enable it you need to set the option -labelcommand tablelist::sortByColumn. If you don't do that there is no auto-sort.

crv: How obvious -- And embarrassing!! Thanks for the help.

JMN 2006-10-12 There's a serious vertical scrolling problem with Tablelist 4.4 & 4.5, at least when using Tk 8.5a4/8.5a5 on windows. If you grab the slider and bring it to the bottom and release your mouse button, the slider does a little 'dance' in the scrollbar trough.. jumping up and down a couple of times before settling a little bit above the bottom. During this dance the tablelist area warps and refreshes while trying to keep up. If you try to drag the slider to the bottom but don't release the mouse button - the problem is even worse. You get a continous mad jumping back and forth of the slider up and down by half a line-height or so.

This effect can be seen on the embeddedWindows.tcl demo included in the tablelist demos, but is not related to embedded windows. A simple table with textual entries seems to exhibit the problem.

I haven't yet filed a bug report. Will do when I get a chance to isolate a minimal demo script, and test on other platforms.

In the meantime - for me Tablelist 4.3 gives superior feel & performance for scrolling than the later versions.

Csaba Nemethi 2006-10-12: This issue is related to some changes made in the text widget implementation in Tk 8.5. Interestingly, I could reproduce it on Mac OS X but not on Linux (I have no Tk 8.5 release for Windows yet). The problem is not present when working with the stable Tk versions 8.0 - 8.4. I will try to adapt the Tablelist code to the modified text widget behavior in Tk 8.5, in order to eliminate this effect.

Csaba Nemethi 2006-10-14: I have found a simple solution to the scrolling problem experienced when using Tk 8.5. Patch the Tablelist 4.5 distribution file tablelistWidget.tcl by inserting the following code after its line #3806:

foreach {x y width height baselinePos} [$w dlineinfo $topTextIdx] {}
if {$y < 0} {
    incr topRow

The patched version works as expected with all Tk versions 8.0 - 8.5. This fix will be contained in the next Tablelist release.

Csaba Nemethi 2007-02-04: The effect described by JMN is no longer present in the new Tablelist version 4.6.

JMN 2007-02-18: I'm not convinced this is fixed.. the embeddedWindows.tcl demo still has jumpy behaviour for me. Also - there appear to be at least 2 different releases of tablelist out there marked with version 4.6 One of them, from tklib0.4.1.0 doesn't function with Tile 0.8.0 (complains 'can't read "tile::curentTheme").. the other (direct from Csaba's site) works ok. I think a version bump somewhere might be in order.

Csaba Nemethi 2007-02-18: I have made the above correction, but, unfortunately, with a typo (actually, the result of copy & paste). In the Tablelist 4.6 distribution file tablelistWidget.tcl, this correction starts in line #3874. Please patch that line by replacing the erronous "btmTextIdx" with "topTextIdx", and report whether the corrected version still exhibits the jumpy behavior (it shouldn't).

Which tklib0.4.1.0 do you mean? The only official tklib0.4.1 version was released on November 12 (or 14?), 2005. At that time there was surely no Tablelist version 4.6. In the CVS, the current tklib version has been since November 21, 2005 (i.e., for nearly 15 months). The current Tablelist version in the CVS is identical with the one on my Web site, which is the only Tablelist 4.6 release. I can only imagine that you have an older tklib0.4.1.0 CVS snapshot, which contains an early development state of Tablelist 4.6 (I added the support for tile 0.8 on December 28, 2006).

RT: I'm getting an error: bad text index "+2c-1c" from v4.6 running on Windows XP Tcl/Tk 8.4.9. This problem occurs after creating a row using $tl insert end "" and then iterating through column numbers and calling $tl cellconfigure end,$colnum -text $txt This is embedded in a lot of other code so no example at the moment. I wondered if there could be an issue in configuring multi-line text after creating the row with empty colums? - 12Mar2007 RT Same scenario even when the above "bad text index..." doesn't occur. Clicking anywhere in the widget (on a row or on empty area) generates a bigger error trace:

bad text index "+1c"
    while executing
"::$win selection set $row"
    ("row" arm line 10)
    invoked from within
"switch $data(-selecttype) {
        row {
            if {[string compare $data(-selectmode) "multiple"] == 0} {
                 if {[::$win selection includes $row]} {
    (procedure "tablelist::beginSelect" line 4)
    invoked from within
"tablelist::beginSelect $tablelist::W  $tablelist::priv(row) $tablelist::priv(col)"
  invoked from within
"if {[winfo exists .joe.t.body]} {
            foreach {tablelist::W tablelist::x tablelist::y}  [tablelist::convEventFields .joe.t.body 1238 156] {}

  (command bound to event)

RT: All seems fine when I wrap the text portions of each cell into the item and then to $lt insert end $item That is the coding style I've retreated to at this point.

Csaba Nemethi 2007-06-27: Both bugs above are fixed in Tablelist 4.7.

Bryan Oakley 2007-11-10: I'm getting a 'bad text index ""' with version 4.8, which I did not get with 4.6.

MHo 2008-02-20: From time to time, I see this behaviour: I try to insert a list (of rows) in to a tablelist widget, where the list can have, e.g., the following format:

a b {c d} e

The problem is, the 3rd item should be inserted as one item into one cell. But tablelist interprets this as two columns. The widget only has one column, so the 2nd word (d) is lost after the insert operation...

The Question is: How to form a "multi word element" so tablelist treats that as one column during insertions???? If I do this:

.widget insert end [list {a b}]

this displays ok, but after getting the value back,I see {a b} in my code and have to do a join.... Problably I'm totally quoting-confused actually...

Csaba Nemethi 2008-02-22: You are using the insert subcommand correctly. But please note that the command

.widget get end

will return a list of strings, whose external representation is {a b}. To get back the string inserted into the only cell of the last row, use

lindex [.widget get end] 0


.widget cellcget end,0 -text

MHo 2008-04-11:

  • (How) can I prevent \n-Characters from switching to multi-line mode? Can I use -formatcommand to hide the newlines only from beeing displayed (not altering the real content of the cell)? And then, what is the format if I edit such a formatted cell - will the content then be displayed as multiple lines?
  • Can I give a uniform height (specified in pixels) to all rows of a table?
  • (How) can I tell tablelist that the value inside all cells of a column is to be interpreted as an image handle? Up to now, I have to do a cellconfigure end,0 -image x e.g. for each cell. Even -formatcommand is not the solution, because the callback cannot give back an image....

Csaba Nemethi 2008-04-12:

  • As described in the INTERACTIVE CELL EDITING section of the reference manual, the text inserted into the temporary embedded widget will be the result of the -formatcommand column configuration option, and it can be changed further with the aid of the -editstartcommand option. In this way, you can suppress the newline characters not only when displaying the elements, but also when editing them.
  • Tablelist rows are of dynamic (optimal) height, and there is no way to specify a uniform height for the rows. You can, however, make all the rows higher by the same amount, by using the -spacing option.
  • Images can only be specified for individual cells, with the aid of the cellconfigure subcommand.

MHo: Thanks for your fast response! Meanwhile, I achieved uniform row heights by interting a dummy image...

Martyn Smith 200_-04-21: The idea of using the contents of a cell as the image name is very good, I currently have to loop over the whole table adding images using after but this takes alot of time and reduces the response of the program.

MHo: Usually, I don't want the contents of edit fields to be selected right after navigating to them. If I click in an editable table cell the value isn't selected (what I prefer). If I then move to the next/prior cell via tab/down/up/etc., the value of that field is selected, so it is after invoking the editcell subcommand. Can I alter this behaviour without rewriting all bindings?

Csaba Nemethi 2008-04-28:

This behavior is intentional and cannot be changed without altering the Tablelist code. It is implemented this way in order to conform to the common behavior exhibited by entry widgets when using keyboard navigation with Tab and Shift-Tab.

MHo: Ok. But I wonder if could I work around this providing my own entry field and using -editwinpath...

plasma 2009-10-25 04:27:36:

I am familiar with the commands getcolumns and getcells.How to get the elements of a particular column starting from a particular(say the active) row?

Csaba Nemethi 2009-10-25:

Here is an example, in which row is supposed to be a numerical row index (e.g., $tbl index active)

set colContents [$tbl getcolumns $col]
set colContentsRange [lrange $colContents $row end]

Alternatively, you can use the getcells subcommand:

set count [$tbl size]
for {set _row $row} {$_row < $count} {incr _row} {
    lappend colContentsRange [$tbl getcells $_row,$col]

PO 2010-01-29: I recently had the need to fill a tablelist by column. The data comes from lists of differing size holding the column data. Tablelist does not directly support such a feature, but Csaba told me the following workaround:

package require tablelist

tablelist::tablelist .tl \
      -stripebackground #e0e8f0 \
      -showseparators yes
pack .tl

# A list of two coluumn lists.
set colList {
    { 1 2 3 4 5 6 7 }
    { a b c d e f g h i }

.tl configure -columns {0 "Column 1" right
                        0 "Column 2" left}

# Determine max. number of rows.
set maxRows 0
foreach col $colList {
    set numRows [llength $col]
    if { $numRows > $maxRows } {
        set maxRows $numRows

# Insert maxRows empty lines.
for {set row 0} {$row < $maxRows} {incr row} {
    .tl insert end {}
# Fill columns with the data from the lists.
set colNum 0
foreach col $colList {
    .tl columnconfigure $colNum -text $col
    incr colNum

WHD 2010-10-27 18:15:53: Is it possible to register my own widget types for interactive cell editing?

sai: Hello, I wish the following example of gridplus2 in winXP that present error messages. But it's OK in Win7. TCL :ActiveTCL 8.5 ,Tablelist:5.9


package require gridplus 
namespace import gridplus::*

gridplus tablelist .mytable {
   4 Column1
   4 Column2
   0 Column3

gridplus layout .main -wtitle {Tablelist Example} {

pack .main

error message

can't access "::tablelist::ns.::data": parent namespace doesn't exist
can't access "::tablelist::ns.::data": parent namespace doesn't exist
    while executing
"upvar ::tablelist::ns${win}::data data"
    (procedure "tablelist::addActiveTag" line 2)
    invoked from within
"tablelist::addActiveTag ."
    (command bound to event)

Csaba Nemethi 2013-06-16: You got this error message on Windows XT because your test script was "tablelist.tcl", other than on Windows 7, where you chose a different name for it. This is no Tablelist-specific problem. See the paragraphs following the "Basic usage:" section above for details.

Sai: Thank you very much,as you say I name the script "tablelist.tcl".

ARR 2013-09-28: Is it possible to control the vertical alignment of wrapped text in a cell? I think the nice new 5.9 -valign option controls embedded images and windows but not text. As a workaround I can use embedded windows with labels and -wraplength but that does not work fine if colums are expanded or when the user resizes a column becase the -wraplength value is not updated. Any hints to make it better?

JM 2/1/2017, I may be doing something wrong but I cannot get tablelist to be found with "package require" inside a tclkit VFS. I placed the dir "tablelist_common5.12.1" inside the demo minimum script: C:\Tcl\tclkit\hello.vfs\lib

just to make sure, I also copied the http library and it does not complain about not being located.

I am using tclkit-8.5.9-win32-x86_64 under Windows7

MHo: Hm, this works for me, although at most I am using 32bit starpacks. The structure there is as follows:

>c:\Users\matthiasu\usr\pgm\tcl\usr\Tst\mailer\mailer3.vfs\lib\tablelist5.15 tree /f /a
Auflistung der Ordnerpfade für Volume Windows
Volumeseriennummer : 00000039 FCEC:BFEA
|   pkgIndex.tcl
|   tablelist.tcl
|   tablelistPublic.tcl
|   tablelist_tile.tcl

JOB - 2018-01-05 20:34:42

To reference tablelist within a starkit vfs, I usually use the following code sequence in the main.tcl file (which is on the very top of the vfs branch):

# !/usr/bin/ksh
# next line starts wish \
exec wish "$0" "$@"

if {[catch {
        package require starkit
        if {[starkit::startup] eq "sourced"} { return } }]} {

        namespace eval ::starkit {
                if {[set this [info script]] == ""} {
                        set this [info nameofexecutable]
                variable topdir [file normalize [file dirname $this]]

# specify, where to find specific packages:
set auto_path [linsert $auto_path 0 [file join $::starkit::topdir "lib"]]

package require Tablelist_tile


Make sure that auto_path list variable is set accordingly and the tablelist package is available in the sibling lib directory.

MHo 2019-01-05 - if multiple rows are selected, how to process them with a context menu? The right mouse click, which shows the menu, clears the selection beforehand...

Csaba Nemethi 2019-01-10 This is not right. The Tablelist code doesn't contain any binding for the <Button-3> event within the body of a tablelist widget.

MHo 2019-01-14: I'm sorry, you are right of course. In that case I'm using tablelist in the context of gridplus2 which seem to handle this then.....