A Ttk widget that provides both tree-browsing capabilities and multicolumn listbox capabilities.
https://www.tcl-lang.org/man/tcl/TkCmd/ttk_treeview.htm
Related widgets can be found on the wiki page treeview.
Some configuration options can be found on ttk::style examples
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).
The basics of this widget are:
package require Tk ttk::style theme use 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]
# 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
If you want to programmatically select a specific item in the treeview, it is best to give the items an -id when they get inserted into the treewidget using the insert subcommand. This option must be given after the parent and index arguments and before adding other options. Then, use this id to select an item:
.tree insert {} end -id myitem2 -text "my text here" .tree selection set myitem2
Note: you cannot use the -tags option for an item to identify it with the `selection` subcommand.
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:
% .tree selection {Item 2} {Item 2-1} {Item 2-2} {Item 2-3} {Item 3}
% .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 {}]
HaO 2016-05-12
Items with big fonts overlap:
image create photo Img -height 5 -width 5 Img put red -to 0 0 4 4 pack [ttk::treeview .t] -fill both -expand true .t tag configure t -font {size 20} -image Img set p [.t insert {} end -text A -tag t -open 1] .t insert $p end -text B -tag t -open 1
Rich wrote:
The rowheight on ttk::treeview does not auto-adjust for the font height of that which it contains. You have to adjust it, using an undocumented method.
See here: [L1 ]. Look at the -rowheight option.
bll 2016-5-12: This:
-rowheight [expr {round($fontsize*2/[tk scaling])}]
seems to work right (assuming fontsize is in points).
HaO 2017-11-06: Here is the full example again:
image create photo Img -height 5 -width 5 Img put red -to 0 0 4 4 font create LabelFont -size 20 label .test -text M -font LabelFont ttk::style configure Treeview -rowheight [winfo reqheight .test] -font LabelFont destroy .test pack [ttk::treeview .t] -fill both -expand true set p [.t insert {} end -text Text -image Img] .t insert $p end -text B -open 1
MHo 2016-06-29: with -selectmode none, cursor up/down beyond the visible items does not scroll the visible items...
AndyM 2019-08-02: When tabbing into a treeview I would have expected to see some focus indicator on the item in the treeview window, for example a dotted border around the item with the focus. There is an example above of pro-grammatically adding a border to an entry, but I have been unable to make this work.
APE 2020-02-15 : a simple example of treeview use to display a table. It needs to configure the style, but I did not find working examples for treeview.
# use of ttk::treeview to build a table # proc newTable # creates a new treeview configured as a table proc newTable {w colnames} { # create the tree showing headings only, and define column names set t [ttk::treeview $w.tree -show headings -columns $colnames] # set the text display for columns headers foreach colname $colnames { $t heading $colname -text $colname } pack $t -expand 1 -fill both return $t } # proc newRow # creates a new row in the treeview and optionally set values proc newRow {t {values ""}} { # insert a new item set item [$t insert {} end] # fill each column with valu foreach col [$t cget -columns] val $values { $t set $item $col $val } } # example # -- create a new table set table [newTable . [list col1 col2 col3 col4]] # -- set values for all columns newRow $table [list 1 2 3 4] # -- add an empty row newRow $table # -- add a row with 2 values (fills 2 first columns) newRow $table [list "value one" "value two"]