Version 31 of ttk::treeview

Updated 2014-02-26 16:40:30 by pooryorick

A Ttk widget that provides both tree-browsing capabilities and multicolumn listbox capabilities.

http://www.tcl.tk/man/tcl8.5/TkCmd/ttk_treeview.htm

More information on the wiki page treeview.


The screenshot below shows the treeview as part of a larger program (using the clam theme). There is a header and 6 entries (where two are one level down).

http://tcl.typoscriptics.de/misc/tile-treeview.png


The basics of this widget are:

 package require tile
 tile::setTheme clam
 # create it:
 ttk::treeview .tree
 pack .tree -expand 1 -fill both
 # insert an entry at the root level:
 set entry1 [.tree insert {} end -text "first item"]
 # and a second one:
 set entry2 [.tree insert {} end -text "second item"]
 # insert a new level with entry1 as parent:
 .tree insert $entry1 end -text "a sublevel"
 # insert another item under this one:
 .tree insert $entry1 end -text "another item"
 # suppose, one item is selected.
 # we can then delete it thus:
 .tree delete [.tree selection]

BAS

 # Also, to add the heading:
 .tree heading #0 -text Features
 # I also like the heading a little closer to the frame
 .tree configure -padding {0 0 0 0}

SLB For an example of how to implement sorting in treeview see Tile Table


MHo 2008-04-09: Does someone know why a horizontal scrollbar does not work properly in conjunction with this widget? It seems that the hsb never gets updated.
D. McC 2008-04-12: Have you specified minimum column widths with the -minwidth option? I used to have this problem too, and it went away when I specified minimum widths.
MHo: No, haven't tried yet. Switched the whole GUI of my app to BWidgets because I had other problems with tile, too. MHo 09-nov-2008: With -stretch 1, the scrollbar is missing, with -stretch 0, it's there!
Luis Calvo 2008-11-28: Hi! I have detected the same "bug" even with -minwidth option at columns. You can find the bug in the 8.5.5 tcl demo: If you take the tcl multi-column list of countries sample and you increase a width column, the x-scroll is working but you can not select or resize the new area. Thanks anyway!


JH I found the old-school border style of treeview on xpnative to be unsatisfactory. Pat pointed out this helpful alternative layout:

    ttk::style layout Treeview {
      Entry.field -sticky news -border 2 -children {
        Treeview.padding -sticky news -children {
            Treeview.treearea -sticky news
        }
      }
    }

You can remove the Entry.field outer part to have purely no border as well. This is good when wrapping it in something like widget::scrolledwindow.


ofv 2009-05-30: I've looked at ttk::treeview source and it seems that one key requirement was completely overlooked: when a node is expanded, the column holding the tree may need to expand for accommodating the new visible items, reflecting the width change on the associated horizontal scrollbar (if any). Right now the code handles the tree as a fixed-width column, much on the way a listbox does. This problem appears on different instances, even if you get the horizontal scrollbar to work with the -minwidth trick. It is not possible to select a node by clicking on it when it is too nested so that it is drawn to the right of the initial visible area. When you have several columns, the tree items are partially drawn over the adyacent columns if there is no space on the tree's column, etc. See the bugs on the SF project page for details. I don't recommend using ttk::treeview unless you know in advance that the tree items will not require more horizontal space than the assigned column width.


snehanish - 2010-05-27 04:25:40

in tree mode ( -show tree) is it not possible to put index number in integer foam.

i mean first column in tree mode always give row numbers. whenever we delete an item the row number should be updated.

for example lets have height of treeview is 10, so we have 10 rows , column 0 indicate 1 to 10 in integer. if i delete item 5 then it should update all index numbers.

if you could add this feature then it would be great.

Thanks

hae 2010-05-27

If you want this feature, then put it into the Tcl feature request tracker


makr 2011-05-17: Rich gave a small example in his clt post "Is this a bug or feature of ttk::treeview?" <https://groups.google.com/groups/search?as_umsgid=9414edd2-90a3-4ccb-a974-47f512f9577b%40l6g2000vbn.googlegroups.com%|%[email protected]%|% >:

ttk::treeview .tree
pack .tree -side top

.tree insert {} end -id "Item 1" -text "Item 1"
.tree insert {} end -id "Item 2" -text "Item 2"
.tree insert {} end -id "Item 3" -text "Item 3"

.tree insert "Item 1" end -id "Item 1-1" -text "Item 1-1"
.tree insert "Item 1" end -id "Item 1-2" -text "Item 1-2"
.tree insert "Item 1" end -id "Item 1-3" -text "Item 1-3"

.tree insert "Item 2" end -id "Item 2-1" -text "Item 2-1"
.tree insert "Item 2" end -id "Item 2-2" -text "Item 2-2"
.tree insert "Item 2" end -id "Item 2-3" -text "Item 2-3"

Ensure "Item 2" is closed, i.e. the sub-items are not displayed. With this example you can then observe an interesting selection behavior:

  • Click "Item 2", then Shift-Click "Item 3". Will lead to the following result
% .tree selection
{Item 2} {Item 2-1} {Item 2-2} {Item 2-3} {Item 3}
  • Click "Item 2", then Ctrl-Click "Item 3". Will lead to the following result
% .tree selection
{Item 2} {Item 3}

MG 2013-01-31 I wrote some code to allow a user to type in a treeview to select the next item which starts with the given prefix. Pressing any non-printing character (or space, as there's an existing binding for that) cancels, and it resets after a short delay (1.3 seconds, by default).

If a row has a -text value set, it uses that. Otherwise, it uses the first non-empty item in its -values. Lightly tested in Tk 8.5 and 8.6.

bind Treeview <KeyPress> [list ::tv::treeviewKeyPress %W %A %K]
bind Treeview <KeyRelease> [list ::tv::treeviewKeyPressReset %A]
bind Treeview <FocusIn> [list ::tv::treeviewKeyPressReset ""]
bind Treeview <FocusOut> [list ::tv::treeviewKeyPressReset ""]

::tv::treeviewKeyPressReset

#: proc ::tv::treeviewKeyPress
#: arg tree Treeview widget
#: arg char The character typed; may be empty
#: arg keysym The keysym for the key pressed
#: desc Handle a keypress in a Treeview to allow typing to select an entry
#: return nothing
proc ::tv::treeviewKeyPress {tree char keysym} {
  variable tvkp;

  if { $char in [list "" " " "\t" "\n"] || $keysym eq "space"} {
       treeviewKeyPressReset;
       return;
     }

  catch {after cancel $tvkp(afterid)}

  if { $tvkp(error) } {
       bell -displayof $tree
     } elseif { $tvkp(reset) } {
       # set everything up
       set tvkp(reset) 0
       set sel [$tree selection]
       if { ![llength $sel] } {
            set tvkp(startid) ""
          } else {
            set tvkp(startid) [lindex $sel 0]
          }
       set tvkp(str) $char
       set tvkp(ids) [treeviewRecursiveListIDs $tree ""]
       if { ![llength $tvkp(ids)] } {
            set tvkp(error) 1
            bell -displayof $tree
          }
       set inc 0
     } else {
       append tvkp(str) $char
       set inc 1
     }

  $tree selection set [list]
  $tree focus {}
  if { !$tvkp(error) } {
       set len [string length $tvkp(str)]
       if { $tvkp(startid) eq "" } {
            set index 0
          } else {
            set index [lsearch -exact $tvkp(ids) $tvkp(startid)]
            if { !$inc } {
                 incr index
                 if { $index == [llength $tvkp(ids)] } {
                      set index 0
                    }
               }
          }
       set ids [concat [lrange $tvkp(ids) $index end] [lrange $tvkp(ids) 0 $index-1]]
       set match ""
       foreach x $ids {
         if { [set text [$tree item $x -text]] eq "" } {
              set text [lsearch -inline -glob [$tree item $x -values] "?*"]
            }
         if { $text eq "" } {
              continue;
            }
         if { [string equal -nocase -length $len $tvkp(str) $text] } {
              set match $x
              break;
            }
       }
       if { $match ne "" } {
            $tree sel set [list $x]
            $tree focus $x
            $tree see $x
            set tvkp(startid) $x
          } else {
            set tvkp(error) 1
            bell -displayof $tree
          }
     }

  set tvkp(afterid) [after $tvkp(aftertime) [list ::tv::treeviewKeyPressReset]]

  return;


};# ::tv::treeviewKeyPress

#: proc ::tv::treeviewKeyPressReset
#: arg char Character generated if this was triggered by a key release; only reset for non-printable keys ($char eq "")
#: desc Reset the $tvkp array used to hold state data for treeview keypresses
#: return nothing
proc ::tv::treeviewKeyPressReset {{char ""}} {
  variable tvkp;

  if { $char ne "" } {
       return;
     }

  set tvkp(str) ""
  set tvkp(startid) ""
  set tvkp(ids) [list]
  set tvkp(reset) 1
  set tvkp(error) 0
  if { [info exists tvkp(afterid)] } {
       catch {after cancel $tvkp(afterid)}
     }
  set tvkp(afterid) ""
  set tvkp(aftertime) 1300

  return;

};# ::tv::treeviewKeyPressReset

#: proc ::tv::treeviewRecursiveListIDs
#: arg tree Tree widget
#: arg id parent id
#: desc Return a list of $id and all its children in the tree widget $tree. Used
#: desc recursively for building a list of all IDs in order
#: return list of ids
proc ::tv::treeviewRecursiveListIDs {tree id} {

  if { ![winfo exists $tree] || ![$tree exists $id] } {
       return;
     }

  set res [list]
  if { $id ne "" } {
       lappend res $id
     }
  foreach x [$tree children $id] {
    lappend res {*}[treeviewRecursiveListIDs $tree $x]
  }

  return $res;

};# ::tv::treeviewRecursiveListIDs

Sarnold uses a BWidget Tree in which some data is associated with each entry. ttk::treeview does not seem - to my great surprise - to handle other data than the text. Is it true ? Is adding such a feature planned ?


nscerqueira 2013-10-3 How to delete all the items from a ttk::tree widget

    .tree delete [.tree children {}]