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 [BWidget]s 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 http://sourceforge.net/tracker/?group_id=12997&atid=362997%|%Tcl feature request tracker%|% ---- [makr] 2011-05-17: ''Rich'' gave a small example in his [comp.lang.tcl%|%clt] post "Is this a bug or feature of [ttk::treeview]?" : ====== 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 [list ::tv::treeviewKeyPress %W %A %K] bind Treeview [list ::tv::treeviewKeyPressReset %A] bind Treeview [list ::tv::treeviewKeyPressReset ""] bind Treeview [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 ====== <> Widget