Updated 2017-03-31 08:55:49 by torsten
What: TkTreeCtrl
Where: http://tktreectrl.sourceforge.net/
Description: multi-column hierarchical listbox widget for Tk. It is a stubs-enabled extension (written in C). Builds and works on Windows, Unix/Linux (with Gtk+ now supported in version 2.3), and Mac OSX, including any of the platforms ActiveTcl runs on.
Currently at version 2.4.1
Updated: 2011-10-17
Contact: See web site


Screenshots and homepage: http://tktreectrl.sourceforge.net/

You can download win32 binaries, and there is a nice demo and docs included.

The easiest way to obtain a working copy of treectrl for many platforms is to simply use the binaries in ActiveTcl.

Doesn't only do tree widgets, it can also do fancy image thumbnail tables - see the demo. It also supports tiled background images similar to what can be found in the Coccinella tree widget http://hem.fyristorg.com/matben/.

davidw has a version of tktreectrl with some enhancements . The source is available at http://github.com/davidw/tktreectrl/tree/master . He has added

  • a -fillstripes option, that attempts to fill in the entire space occupied by the widget - this is useful if you have alternating background colors.
  • a -selectionvisible option that takes the place of a compile time flag, indicating whether it's possible to select elements that are not currently visible.

MAK (19 Jan 2005) If you use TkTreeCtrl, you'd be well advised to be very scrupulous of your code that uses it whenever you upgrade to a new version. There has been a tendency on more than one occasion for incompatible changes being made without any notice or mention in the ChangeLog, and sometimes without a version number change.


For a tutorial and style intro, look here: http://tktreectrl.sourceforge.net/Understanding%20TkTreeCtrl.html

Components of a treectrl

The widget consists of at least one column (for table-like output). Each entry in the widget is called an item and reaches over all columns. The items are composed by adding some elements together to styles. The styles are applied to the items and then it shows up in the widget. In other words (taken from the manual page largely):

  • element: The smallest building block. One or more elements together can be combined to a style, which can be considered as a template for an item. These are the possible element types: bitmap, border, image, rect, and text.
  • item: A set of elements. The look of the items is desribed by styles.
  • styles: Could be considered as a geometry manager for the elements of one item.

A short example

Now let us use this knowledge to create a little example. We first create the widget, then configure it to have one column. Our column will get a label called „My texts" and the column should use the whole width of the widget by default. Before we can add our first item (i.e. row of the table), we need to specify what elements the item should consist of (we just make a text element here called e1) and in what style the element should appear (called s1 here). We need to assign each column (or each item) to a style, and each style consists of elements. The text of a cell is to be put inside a text element (that itself is „inside“ of a style).
package require treectrl
treectrl .t
pack .t
# create an element, that should hold the text of the cell later:
.t element create el1 text
# create a style to be used for the cells:
.t style create s1
# tell the style s1 that it should consist of the text element e1:
.t style elements s1 el1
# now, add a new column to the table and assign the items of that column (which are added in the next step) the style s1
.t column create -text "My texts" -expand yes -itemstyle s1
# now, we are ready to add the first item (.i.e the first row of the table):
# create a new item as a new child of the always existing root item:
set itm [.t item create -parent root]
# give the item a label:
# (we use a convenience command here that assigns the given text to the first text element found in this cell)
# (Otherwise, the command should be: .t item element configure $itm 0 el1 -text "Hello World")
.t item text $itm 0 "Hello World"
# add another item:
set item [.t item create -parent root]
.t item text $item 0 "And good luck with treectrl"

This is it. An item saying Hello World should appear and another saying "And good luck with treectrl“.

Note, that no interaction is visible with this table as it is. You can click on an item, but it will not be highlightes. This is, because we have not specified a selection rectangle and added it to the s1 style yet. If you do this, the table will visually show which items have been clicked on. So, here is the initial example using a more sophisticated styling, resulting in something that is quite close to the listbox provided by Tk itself:
package require treectrl
treectrl .t
pack .t
# create an element, that should hold the text of the cell later:
# specify that the font will be black on normal items and white on selected items
.t element create el1 text -fill {white {selected focus} black {selected !focus}}
# create an element, that should be used a selection marker:
.t element create selectionRectangle rect -fill {#4c70d6 {selected focus} #d4d4d4 {selected !focus}}
# create a style to be used for the cells:
.t style create s1
# tell the style s1 that it should consist of the selection marker first
# and on top of that the text element should be drawn. The order is important since
# the reverse order would hide the text below the selectionRectangle when the item is selected
.t style elements s1 {selectionRectangle el1}
# to make the selectionRectangle visible, we need to specify that it must surround the text element
# and the rectangle should expand east to west to use any extra space and also add some padding vertically
.t style layout s1 selectionRectangle -union el1 -iexpand ew -pady {0 1}
# now, add a new column to the table and assign the items of that column (which are added in the next step) the style s1
.t column create -text "My texts" -expand yes -itemstyle s1
# now, we are ready to add the first item (.i.e the first row of the table):
# create a new item as a new child of the always existing root item:
set itm [.t item create -parent root]
# give the item a label:
# (we use a convenience command here that assigns the given text to the first text element found in this cell)
# (Otherwise, the command should be: .t item element configure $itm 0 el1 -text "Hello World")
.t item text $itm 0 "Hello World"
# add another item:
set item [.t item create -parent root]
.t item text $item 0 "And good luck with treectrl“

IMA 2004-11-22: Does anybody know how to edit items in place in TkTreeCtrl? Thanks

SL 2008-12-17: See TkTreeCtrl - edit text items in place - example

Peter Newman 23 November 2004: 1) See the Explorer demos (they have filename editing). Or; 2) Use item bbox' to find out where the item to be edited is, and place' your entry or whatever widget there.

IMA 2004-11-24: Hi Peter, the explorer demo in tktreectrl 1.1.0 I downloaded does not allow to edit anything (running on Linux RH 8.0) I've found the following code:
set ::TreeCtrl::Priv(edit,$T) {e2}
set ::TreeCtrl::Priv(sensitive,$T) {
    {name styName e1 e2}
}
set ::TreeCtrl::Priv(dragimage,$T) {
    {name styName e1 e2}
}

$T notify bind $T <Edit-accept> {
    %T item text %I 0 %t
}

Is this supposed to allow editing? Thanks

Peter Newman 25 November 2004: 1) The filename editing works under Windows 95/98/XP. I don't see why it shouldn't work under Linux (though I suppose you could argue that a perfect emulation of Windows Explorer shouldn't work on Linux). 2) To invoke the editing; put the mouse cursor on the filename to be edited. then click once; wait about 1 second; then click again. 3) Yes, the code above seems to be part of the editing support. And there's a whole lot more code in filelist-bindings.tcl'. 4) As far as I can see, that code uses the item bbox' technique I suggested above. But it seems way more complex that you need. Don't see why it needs more than 10 lines (though I suppose the `treectrl' version's complexity is because they're trying to emulate Explorer exactly).

IMA 2004-11-25: Thanks Peter! It works indeed. It's just so annoyingly slow... I guess I was too impatient to wait that second:) Thanks again for great support:)

TJM 2005-10-03 How dependent is TkTreeCtrl on Tk 8.4? Will it work with Tk 8.0.5?

JH While you could backport it to Tk 8.4, it would require some work. You would have to remove the use of class procs and any references to UTF-based APIs. The question is, why still bother with 8.0.5?

escargo Everyone does not have the freedom to update the available platform; for example, if vendor X delivers their product with Tcl8/Tk8 (and doesn't provide a build environment), you might not be able to use newer code.

TJM 2005-10-04 Thanks for the confirmation JH. It's a matter of at least a week's worth of work for me, making sure all of the other libraries my project depends on work with 8.4. 'Spose I'll have to do at some point anyway.

peterc 2008-03-07: escargo, this is why I'd almost always recommend app distribution using starpacks. That way the Tcl you're designing for is always the Tcl you've got, since you've got your Tcl basekit and libraries bundled inside your executable's vfs. Doing this, you can safely ignore the cruft of ancient Tcl installations and keep your code up to date with the modern world :-).

MJ - It has taken me quite some time to create a simple tree with text elements that shows the currently active item. This is what I came up with, I hope it will be useful for others.
package require treectrl
treectrl .t -showheader 0 -selectmode single -showroot 0 -yscrollcommand {.y set}
scrollbar .y -ori vert -command ".t yview"
pack .y  -side right -fill y
pack .t  -side right -fill both -expand 1
set columnID [.t column create -text "Column 0"]
.t configure -treecolumn $columnID

.t element create el1 text 
.t element create el2 rect -showfocus yes

 .t style create s1
 .t style elements s1 [list el1 el2]

.t style layout s1 el2 -union el1

.t configure -defaultstyle s1

# easily add a node with text $text as a child of $parent (the root is specified by the string "root")

proc add_node {parent text} {
    set itemID [.t item create -button yes ]
    .t item element configure $itemID 0 el1 -text $text
    .t item collapse $itemID
    .t item lastchild $parent $itemID
    return $itemID    
}

# because the default Right and Left arrow keys don't do anything useful in this case,
# redefine the bindings to expand or collaps an item (or the item and all children with Ctrl)

bind TreeCtrl <Key-Right>         {%W item expand   [%W item id active]}
bind TreeCtrl <Key-Left>          {%W item collapse [%W item id active] }
bind TreeCtrl <Control-Key-Right> {%W item expand   [%W item id active] -recurse} 
bind TreeCtrl <Control-Key-Left>  {%W item collapse [%W item id active] -recurse}

# add some nodes
for {set i 0} {$i < 200} {incr i} {
    add_node [add_node root a$i] b 
    add_node [add_node root c$i] d 
}

And for the adventurous, a MegaWidget (requires Tcl 8.5)
package require Tcl 8.5
package require treectrl
package provide simpletree 0.1

proc simpletree {name args} { 
    frame $name

    treectrl $name.t  -showheader 0 -showroot 0 -selectmode single \
        -yscrollcommand [list $name.y set]\
        -xscrollcommand [list $name.x set] {*}$args
    scrollbar $name.y -ori vertical   -command [list $name.t yview]
    scrollbar $name.x -ori horizontal -command [list $name.t xview]
    grid $name.t $name.y -sticky news
    grid $name.x  -sticky news
    grid rowconfig $name 0 -weight 1
    grid columnconfig $name 0 -weight 1

    set columnID [$name.t column create]
    $name.t configure -treecolumn $columnID

    $name.t element create el1 text 
    $name.t element create el2 rect -showfocus yes
    $name.t style create s1
    $name.t style elements s1 [list el1 el2]
    $name.t style layout s1 el2 -union el1
    $name.t configure -defaultstyle s1

    bindtags $name.t [lreplace [bindtags $name.t] 0 0 $name]

    bind $name <Key-Right>         {%W item expand   [%W item id active] ; break}
    bind $name <Key-Left>          {%W item collapse [%W item id active] ; break}
    bind $name <Control-Key-Right> {%W item expand   [%W item id active] -recurse; break} 
    bind $name <Control-Key-Left>  {%W item collapse [%W item id active] -recurse; break}

    interp hide {} $name

    proc $name {args} {
      set widget [lindex [info level 0] 0]
      set tree $widget.t
      if {[lindex $args 0] eq "add"} {
          if {([llength $args] < 3) || ([llength $args] > 4)} {
              return -code error -level 1 "wrong # args: should be \"$widget add parent text ?expand|collapse?\""
          }
          lassign $args _ parent text state
          set itemID [$tree item create -button no]
          $tree item element configure $itemID 0 el1 -text $text
          $tree item configure $parent -button yes
          puts $state
          if {$state ne {}} {
              $tree item $state $itemID
          }
          $tree item lastchild $parent $itemID
          return $itemID   
      } {
        return [$tree {*}$args]
      }
    }
    return $name
}

# [HJG] Demo:
simpletree .tc 
pack .tc -expand 1 -fill both

pack [text .tx]
.tc notify bind ConsoleTag <Selection> {
    set msg "Selection for %T: Count=%c  Deselected:%D  Selected:%S \n"
    .tx insert end $msg
}

.tc add root "A"   collapse
.tc add last "A1"

.tc add root "B"   expand
.tc add last "B1"  
.tc add end  "B2"

set x [.tc add root "C"   collapse]
.tc add $x "C1"
.tc add $x "C2"

.tc add root "D"

I was able to compile tktreectrl version 2.2.3 on Mac OS X 10.4.10 from the sources, building against Tcl 8.5b1 (a build against Tcl 8.4 didn't work). The resulting package works nicely on the Apple X11 window manager, but fails using the Aqua version of Tcl/Tk with ...
% package require treectrl
2.2.3
% treectrl .t
Bus error

JH This works fine for me using treectrl shipped with AT 8.4.16.0 and running in AT 8.5.0.0b9.

[aaaaaaaaa] - 2009-06-29 14:51:22

This looks very nice! Is this package available on all platforms? I don't want to start using it only to find out it is only for Windows. (Linux is a must for me.)

hae As it is written on top: Yes it is available for Windows, Unix/Linux, MacOS.

Googie - It's also available for any platform that ActiveTcl supports. It can be found in ActiveState official teapot repository.

JJS - 2014-11-12 - Depending on the platform you want, teacup might be the bearer of bad news:
C:\WINDOWS\system32>teacup search in name treectrl and eq version 2.4.1 and glob platform solaris*
entity   name     version platform
-------- -------- ------- ----------------
redirect treectrl 2.4.1   solaris2.8-sparc Business Edition Only --- License required
redirect treectrl 2.4.1   solaris2.10-ix86 Business Edition Only --- License required
-------- -------- ------- ----------------

jnc Jan 18, 2010 - Anyone know how to detect when the mouse is hovering over the column heading? I hate to bind to the motion event and check the x/y with each mouse move just so I can display a tooltip.

brlcad - 19 April 2010 - Are there any plans to integrate the features of treectrl with the new ttk::tree widget? What are the dominant show-stoppers, if any. It would be really great to have a more powerful core tree widget so that this isn't distributed and managed as a separate package.

[hs] - 2011-03-03 05:08:57

I dont know if I reach the developers of treectrl here: Firstly, thank you for this great work.

A kindly request: What is about the possibility to have more then one header to organize data vertically. Unfortunately, I'm not able to distribute it by myself because I have not the appropriate background. But would be this feature not attractive for one of the next releases?

tnb 03 March 2011 - If you mean multiple adjacent rows of column headers, I've thought about it, I just don't have any good ideas on what the API should look like for such a feature. One idea I had was to allow items to be locked just below the column header so they would scroll horizontally but not vertically, similar to the column -lock option.

[hs] - 2011-03-04 07:12:12

Yes, like the column -lock option, this is what I mean. - Then, for example, it is possible to "title" generic groups which has severel subtypes and so on, and the last types have then records.

SeS - 2011-8-30

Hello, first of all, thank you for this very usefull widget! In my continued efforts to make tG² more and more user friendly and trying to make use of available widgets & functions as much as I can, I have tried to look for ways to enhance the Project Explorer of tG² with regard to opening files. The treectrl widget provides already dragging functionality, but either I am missed the chapter where info is available how to fully utilize the drop functionality or it is simply not yet implemented. I am talking about dragging treectrl objects outside of the treectrl canvas and dropping it on any other type of widget. So, not only dragging and dropping into the same treectrl widget!

With less than 50 lines of additional code to procedure ::TreeCtrl::FileListMotion and something like 10 lines of code for the binding of TreeCtrlFileList <ButtonRelease-1>, I was able to accomplish the extended drag/drop feature. Here a short demo of the end result.

If anybody is interested how I did this and you would like me to elaborate on this in detail, let me know.

[AD] - 2014-04-21 09:19:41

Hello,

I would like to have treectrl selection logic identical to that in Microsoft Windows.

The main difference between the selection logic in treectrl and Windows is that the items react to button press instead to button release. For example: The selection status of an item changes from unselected to selected at the button press event instead of button release.

The biggest problem with that: When I want to drag an item with CTRL key pressed (Copy action) the item status changes from selected to unselected at the moment I press the left mouse button and begin draging. So the item must be unselected before dragging it. This is unlogical.

So basically I could reformulate the question: How to implement Copy-Paste in treectrl by dragging an item with CTRL key pressed?

Thank you.

Best regards

Alexandru Dadalau