Flame ttk::treeview widget lacks one important function for me - inplace editing of the contents. I've decided to try to implement it, though tktreectrl suits more for this task. The main problem is to track focus changes since there is no mechanism in ttk::treeview for this.
JE See also: <URL: http://www.flightlab.com/~joe/repos/themebag/inplace.tcl >.
DDG - 2020-04-14: See dgw::tvmixins for a snit::widget adaptor of the code below which simplifies addition to ttk::treeview widgets.
# BSD license package require Tk 8.5 package provide xtreeview 1.2 namespace eval xtreeview { # intercept all the events changing focus bind XTreeview <<TreeviewSelect>> "+::xtreeview::checkFocus %W" bind XTreeview <ButtonRelease-1> "+::xtreeview::checkFocus %W %x %y" bind XTreeview <KeyRelease> "+::xtreeview::checkFocus %W" bind XTreeview <ButtonPress-4> "+after idle ::xtreeview::updateWnds %W" bind XTreeview <ButtonPress-5> "+after idle ::xtreeview::updateWnds %W" bind XTreeview <MouseWheel> "+after idle ::xtreeview::updateWnds %W" bind XTreeview <B1-Motion> {+if {$ttk::treeview::State(pressMode)=="resize"} { ::xtreeview::updateWnds %W }} bind XTreeview <Configure> "+after idle ::xtreeview::updateWnds %W" bind XTreeview <Home> {%W focus [lindex [%W children {}] 0]} bind XTreeview <End> {%W focus [lindex [%W children {}] end]} # images indicating sort order image create bitmap ::xtreeview::arrow(0) -data { #define arrowUp_width 7 #define arrowUp_height 4 static char arrowUp_bits[] = { 0x08, 0x1c, 0x3e, 0x7f }; } image create bitmap ::xtreeview::arrow(1) -data { #define arrowDown_width 7 #define arrowDown_height 4 static char arrowDown_bits[] = { 0x7f, 0x3e, 0x1c, 0x08 }; } image create bitmap ::xtreeview::arrowBlank -data { #define arrowBlank_width 7 #define arrowBlank_height 4 static char arrowBlank_bits[] = { 0x00, 0x00, 0x00, 0x00 }; } variable curfocus # check, if focus has changed proc checkFocus {w {X {}} {Y {}} } { variable curfocus if {![info exists curfocus($w)]} { set changed 1 } elseif {$curfocus($w)!=[$w focus]} { _clear $w $curfocus($w) set changed 1 } else { set changed 0 } set newfocus [$w focus] if {$changed} { if {$newfocus!=""} { _focus $w $newfocus if {$X!=""} { set col [$w identify column $X $Y] if {$col!=""} { if {$col!="#0"} { set col [$w column $col -id] } } catch {focus $w.$col} } } set curfocus($w) $newfocus updateWnds $w } } # update inplace edit widgets positions proc updateWnds {w} { variable curfocus if {![info exists curfocus($w)]} { return } set item $curfocus($w) if {$item==""} { return } foreach col [concat [$w cget -columns] #0] { set wnd $w.$col if {[winfo exists $wnd]} { set bbox [$w bbox $item $col] if {$bbox==""} { place forget $wnd } else { place $wnd -x [lindex $bbox 0] -y [lindex $bbox 1] -width [lindex $bbox 2] -height [lindex $bbox 3] } } } } # remove all inplace edit widgets proc _clear {w item} { foreach col [concat [$w cget -columns] #0] { set wnd $w.$col if {[winfo exists $wnd]} { destroy $wnd } } } # called when focus item has changed proc _focus {w item} { set cols [$w cget -displaycolumns] if {$cols=="#all"} { set cols [concat #0 [$w cget -columns]] } foreach col $cols { event generate $w <<TreeviewInplaceEdit>> -data [list $col $item] if {[winfo exists $w.$col]} { bind $w.$col <Key-Tab> {focus [tk_focusNext %W]} bind $w.$col <Shift-Key-Tab> {focus [tk_focusPrev %W]} } } } # hierarchical sorting procedure proc _sorttree {tree col direction {isroot 1} {root {}} } { if {$isroot} { if {$col!="#0"} { set col [$tree column $col -id] } set selection [$tree selection] $tree selection remove $selection set focus [$tree focus] $tree focus {} checkFocus $tree } # Build something we can sort set data {} if {$col=="#0"} { foreach row [$tree children $root] { lappend data [list [$tree item $row -text] $row] } } else { foreach row [$tree children $root] { lappend data [list [$tree set $row $col] $row] } } if {$data!=""} { set dir [expr {$direction ? "-decreasing" : "-increasing"}] set r -1 # Now reshuffle the rows into the sorted order foreach info [lsort -dictionary -index 0 $dir $data] { $tree move [lindex $info 1] $root [incr r] if {[$tree item [lindex $info 1] -open]} { _sorttree $tree $col $direction 0 [lindex $info 1] } } } if {$isroot} { # Switch the heading so that it will sort in the opposite direction variable curfocus catch { eval [lindex [after info $curfocus($tree,sorticon)] 0] after cancel $curfocus($tree,sorticon) } set curfocus($tree,sorticon) [after 3000 [list catch [list $tree heading $col -image ::xtreeview::arrowEmpty]]] $tree heading $col -command [namespace code [list _sorttree $tree $col [expr {1-$direction}]]] -image ::xtreeview::arrow($direction) $tree selection set $selection $tree focus $focus checkFocus $tree } } # installs in-place edit bindings, adjusts tree header columns width, assigns column names, installs sorting handlers proc _treeheaders {path {sort true} {treecolumnname {}} } { set tags [bindtags $path] if {[lsearch -exact $tags XTreeview]<0} { bindtags $path [linsert $tags [lsearch -exact $tags Treeview]+1 XTreeview] } set font [::ttk::style lookup [$path cget -style] -font] if {$font==""} { set font TkTextFont } foreach col [$path cget -columns] { if {$col!=""} { if {$sort} { $path heading $col -text $col -command [namespace code [list _sorttree $path $col 0]] } else { $path heading $col -text $col } $path column $col -width [font measure $font @@@@$col] } } if {$treecolumnname!=""} { $path heading #0 -text $treecolumnname $path column #0 -width [font measure $font @@@@$treecolumnname] if {$sort} { $path heading #0 -command [namespace code [list _sorttree $path #0 0]] } } } # helper functions for inplace edit proc _get_value {w column item} { if {$column=="#0"} { return [$w item $item -text] } else { return [$w set $item $column] } } proc _set_value {w column item value} { if {$column=="#0"} { $w item $item -text $value } else { $w set $item $column $value } } proc _update_value {w column item} { variable curfocus set value [_get_value $w $column $item] set newvalue $curfocus($w,$column) if {$value!=$newvalue} { _set_value $w $column $item $newvalue } } # these functions create widgets for in-place edit, use them in your in-place edit handler proc _inplaceEntry {w column item} { variable curfocus set wnd $w.$column ttk::entry $wnd -textvariable [namespace current]::curfocus($w,$column) -width 3 set curfocus($w,$column) [_get_value $w $column $item] bind $wnd <Destroy> [namespace code [list _update_value $w $column $item]] } proc _inplaceEntryButton {w column item script} { variable curfocus set wnd $w.$column ttk::frame $wnd pack [ttk::entry $wnd.e -width 3 -textvariable [namespace current]::curfocus($w,$column)] -side left -fill x -expand true pack [ttk::button $wnd.b -style Toolbutton -text "..." -command [string map [list %v [namespace current]::curfocus($w,$column)] $script]] -side left -fill x set curfocus($w,$column) [_get_value $w $column $item] bind $wnd <Destroy> [namespace code [list _update_value $w $column $item]] } proc _inplaceCheckbutton {w column item {onvalue 1} {offvalue 0} } { variable curfocus set wnd $w.$column ttk::checkbutton $wnd -variable [namespace current]::curfocus($w,$column) -onvalue $onvalue -offvalue $offvalue set curfocus($w,$column) [_get_value $w $column $item] bind $wnd <Destroy> [namespace code [list _update_value $w $column $item]] } proc _inplaceList {w column item values} { variable curfocus set wnd $w.$column ttk::combobox $wnd -textvariable [namespace current]::curfocus($w,$column) -values $values -state readonly set curfocus($w,$column) [_get_value $w $column $item] bind $wnd <Destroy> [namespace code [list _update_value $w $column $item]] } proc _inplaceSpinbox {w column item min max step} { variable curfocus set wnd $w.$column spinbox $wnd -textvariable [namespace current]::curfocus($w,$column) -from $min -to $max -increment $step set curfocus($w,$column) [_get_value $w $column $item] bind $wnd <Destroy> [namespace code [list _update_value $w $column $item]] } } if { $argv0 eq [info script] } { catch {console show} pack [ttk::treeview .tv -columns {bool int list} -show {tree headings} -selectmode extended -yscrollcommand {.sb set}] -fill both -expand true -side left pack [ttk::scrollbar .sb -orient v -command {after idle ::xtreeview::updateWnds .tv;.tv yview}] -fill y -side left xtreeview::_treeheaders .tv true text .tv insert {} end -text {Sample text} -values {true 15 {Letter B}} set i0 [.tv insert {} end -text {Sample text} -values {false 25 {Letter C}}] .tv insert {} end -text {Sample text} -values {true 35 {Letter D}} .tv insert $i0 end -text {Sample subitem} -values {true 45 {Letter A}} for {set i 0} {$i<50} {incr i} { .tv insert $i0 end -text "Subitem $i" -values [list true $i {Letter B}] } bind .tv <<TreeviewInplaceEdit>> { if {[%W children [lindex %d 1]]==""} { switch [lindex %d 0] { {#0} { xtreeview::_inplaceEntry %W {*}%d } {bool} { xtreeview::_inplaceCheckbutton %W {*}%d true false} {int} { xtreeview::_inplaceSpinbox %W {*}%d 0 100 1 } {list} { xtreeview::_inplaceList %W {*}%d {"Letter A" "Letter B" "Letter C" "Letter D"} } } } elseif {[lindex %d 0]=="list"} { xtreeview::_inplaceEntryButton %W {*}%d { set %%v "tree: %W, column,item=%d" } } } }