TreeView Tooltips

Keith Vetter 2009-11-07 : I love tile's treeview widget but one thing it lacks are the virtual events needed for tooltips. Specifically, it lacks the <Enter> and <Leave> events that are needed to know when to post or remove a tooltip window.

This page is mis-titled--there's no code here for actually creating tooltips. Rather this package allows an treeview widget to generate two new virtual events when the mouse moves between rows in the tree. (Taking this and creating actual tooltips is left as an exercise for the reader.)

The two new virtual events for a treeview widget are: <<RowEnter>> and <<RowLeave>>. Both provide five event fields: %d => treeview row id plus %x, %y, %X and %Y. It works by hooking into the <Motion> event, tracking the row the mouse is in and firing events when that changes.

As always, there's some demo code to show how to use it.


namespace eval ::ToolTipTV {}

proc ::ToolTipTV::Init {W} {
    set ::ToolTipTV::LAST($W) ""
    set ::ToolTipTV::AFTERS($W) ""
    bind $W <Motion> [list ::ToolTipTV::_onMotion %W %x %y %X %Y]
}
proc ::ToolTipTV::_onMotion {W x y rootX rootY} {
    variable LAST
    
    set id [$W identify row $x $y]
    set lastId $::ToolTipTV::LAST($W)
    set ::ToolTipTV::LAST($W) $id

    if {$id ne $lastId} {
        after cancel $::ToolTipTV::AFTERS($W)
        if {$lastId ne ""} {
            event generate $W <<RowLeave>> \
                -data $lastId -x $x -y $y -rootx $rootX -rooty $rootY
        }
        if {$id ne ""} {
            set ::ToolTipTV::AFTERS($W) \
                [after 300 event generate $W <<RowEnter>> \
                     -data $id -x $x -y $y -rootx $rootX -rooty $rootY]
        }
    }
}

################################################################
#
# Demo code
#

::ttk::label .msg -font "Times 24 bold" -textvariable ::msg -width 20 \
    -background yellow -borderwidth 2 -relief ridge

::ttk::treeview .tree -height 15 -show tree \
    -yscroll ".vsb set" -xscroll ".hsb set" -selectmode browse
::ttk::scrollbar .vsb -orient vertical -command ".tree yview"
::ttk::scrollbar .hsb -orient horizontal -command ".tree xview"

grid .msg - -sticky ew
grid .tree .vsb -sticky nsew
grid .hsb       -sticky nsew
grid column . 0 -weight 1
grid row    . 1 -weight 1

foreach txt {first second third} {
    set id [.tree insert {} end -text "$txt item" -open 1]
    for {set i [expr {1+int(rand()*5)}]} {$i > 0} {incr i -1} {
        set child [.tree insert $id 0 -text "child $i"]
        for {set j [expr {int(rand()*3)}]} {$j > 0} {incr j -1} {
            .tree insert $child 0 -text "grandchild $i"
        }
    }
}
::ToolTipTV::Init .tree
bind .tree <<RowEnter>> { set ::msg "Entering row %d"}
bind .tree <<RowLeave>> { set ::msg "Leaving row %d"}
return

Discussion

DDG 2020-06-07: on ttk::treeview mixins I created a snit widgetadaptor based on the code above which simplifies the addition of multiple of such small additions such as tooltips, banding stripes to the ttk::treeview widget.