It's a Tcl/Tk tooltip widget inspired by:
https://wiki.tcl-lang.org/page/balloon+help
The original code has been modified to make the tooltip:
Below are several pictures just to glance at the tooltip4.
Bold welcome. The tooltip's font is configured to be "-weight bold -size 11".
More standard. The tooltip's font is configured to be more standard.
Label of danger. The labels are also tooltipped. This one is configured to be an alert.
Button's tip. This button has its own tooltip, being a caller of a balloon at that.
Balloon. The balloon appears at the top right corner. After a while it disappears.
The tooltip4 usage is rather straightforward. Firstly we need package require:
lappend auto_path "dir_of_tooltip4" package require tooltip4
Then we set tooltips with ::tooltip4::tooltip
command for each appropriate widget:
::tooltip4::tooltip widgetpath text ?-option value? # or this way: ::tooltip4 tooltip widgetpath text ?-option value?
For example, having a button .win.but1, we can set its tooltip this way:
::tooltip4 tooltip .win.but1 "It's a tooltip.\n2nd line of it.\n3rd."
To get all or specific settings tooltip4 settings:
::tooltip4::cget ::tooltip4::cget -option ?-option? # or this way: ::tooltip4 cget ::tooltip4 cget -option ?-option?
To set some options:
::tooltip4::configure -option value ?-option value? # or this way: ::tooltip4 config -option value ?-option value?
Note: the options set with configure
command are global, i.e. active for all tooltips. The options set with tooltip
command are local, i.e. active for the specific tooltip.
To make all (or specific) tooltips use the global settings:
::tooltip4::update ?widgetpath?
To disable all tooltips:
::tooltip4::configure -on false
To disable some specific tooltip:
::tooltip4::tooltip widgetpath "" # or this way: ::tooltip4::tooltip widgetpath "old tooltip" -on false
To hide some specific (suspended) tooltip forcedly:
::tooltip4::hide widgetpath
When you click on a widget with tooltip being displayed, the tooltip is hidden. It is the default behavior of tooltip4, but sometimes you need to re-display the hidden tooltip. If the widget is a button, you can include the following command in -command
of the button:
::tooltip4::repaint widgetpath
The normal tooltip has no -geometry
option because it's calculated by tooltip4.
So, with -geometry
option you get a balloon message unrelated to any visible widget (it's made on the toplevel window). The -geometry
option has +X+Y form where X and Y are coordinates of the balloon.
For example:
::tooltip4::tooltip .win "It's a balloon at +1+100 (+X+Y) coordinates" -geometry +1+100 -font {-weight bold -size 12} -alpha 0.8 -fg white -bg black -per10 3000 -pause 1500 -fade 1500
The -pause
and -fade
options make the balloon fade at appearing and disappearing. The -per10
option defines the balloon's duration: the more the longer.
The -geometry
value can include W
and H
wildcards meaning the width and the height of the balloon. This may be useful when you need to show a balloon at a window's edge and should use the balloon's dimensions which are available only after its creation. The X and Y coordinates are calculated by tooltip4 as normal expressions. Of course, they should not include the "+" divider, but this restriction (if any) is easily overcome.
For example:
lassign [split [winfo geometry .win] x+] w h x y set geom "+([expr {$w+$x}]-W-4)+$y" set text "The balloon at the right edge of the window" ::tooltip4 too .win $text -geometry $geom -pause 2000 -fade 2000
As seen in the above examples, the tooltip4 can be used as Tcl ensemble, so that the commands may be shortened.
Below are listed the tooltip4 options that are set with tooltip
and configure
and got with cget
:
-on | switches all tooltips on/off; |
-per10 | a time of exposition per 10 characters (in millisec.); "0" means "eternal"; |
-fade | a time of fading (in millisec.); |
-pause | a pause before displaying tooltips (in millisec.); |
-alpha | an opacity (from 0.0 to 1.0); |
-fg | foreground of tooltip; |
-bg | background of tooltip; |
-bd | borderwidth of tooltip; |
-font | font attributes; |
-padx | X padding for text; |
-pady | Y padding for text; |
-padding | padding for pack. |
The following options are special:
-force | if true, forces the display by 'tooltip' command; |
-index | index of menu item to tip; |
-tag | name of text tag to tip; |
-geometry | geometry (+X+Y) of the balloon. |
You can test the tooltip4 with test2_pave.tcl of the apave package available at:
Note that tooltip4 is still disposed to updating.
Gets the tooltip's option values.
| option names (if empty, returns all options) |
Returns a list of "name value" pairs.
proc ::tooltip4::cget {args} { # Gets the tooltip's option values. # args - option names (if empty, returns all options) # Returns a list of "name value" pairs. if {![llength $args]} { lappend args -on -per10 -fade -pause -fg -bg -bd -padx -pady -padding -font -alpha -text -index -tag } set res [list] foreach n $args { set n [string range $n 1 end] if {[info exists my::ttdata($n)]} { lappend res -$n $my::ttdata($n) } } return $res }
Configurates the tooltip for all widgets.
| options ("name value" pairs) |
The following options are special:
-force | if true, forces the display by 'tooltip' command |
-index | index of menu item to tip |
-tag | name of text tag to tip |
-geometry | geometry (+X+Y) of the balloon |
Returns the list of -force, -geometry, -index, -tag option values.
proc ::tooltip4::configure {args} { # Configurates the tooltip for all widgets. # args - options ("name value" pairs) # The following options are special: # -force - if true, forces the display by 'tooltip' command # -index - index of menu item to tip # -tag - name of text tag to tip # -geometry - geometry (+X+Y) of the balloon # Returns the list of -force, -geometry, -index, -tag option values. set force 0 set index -1 set geo [set tag ""] foreach {n v} $args { switch -glob -- $n { -per10 - -fade - -pause - -fg - -bg - -bd - -alpha - -text - -on - -padx - -pady - -padding { set my::ttdata([string range $n 1 end]) $v } -font {foreach {k v} $v {dict set my::ttdata(font) $k $v}} -force {set force $v} -index {set index $v} -tag {set tag $v} -geometry {set geo $v} default {return -code error "invalid option \"$n\""} } } return [list $force $geo $index $tag] }
Destroys the tooltip's window.
| the tooltip's parent window; optional, default "" |
Returns 1, if the window was really hidden.
proc ::tooltip4::hide {{w {}}} { # Destroys the tooltip's window. # w - the tooltip's parent window # Returns 1, if the window was really hidden. return [expr {![catch {destroy $w.$my::ttdata(wttip)}]}] }
Repaints a tooltip immediately.
| widget's path |
proc ::tooltip4::repaint {w} { # Repaints a tooltip immediately. # w - widget's path if {[winfo exists $w] && [info exists my::ttdata(optvals,$w)]} { ::tooltip4::my::Show $w [dict get $my::ttdata(optvals,$w) -text] yes {} $my::ttdata(optvals,$w) } }
Creates a tooltip for a widget.
| the parent widget's path |
| the tooltip text |
| options ("name value" pairs) |
proc ::tooltip4::tooltip {w text args} { # Creates a tooltip for a widget. # w - the parent widget's path # text - the tooltip text # args - options ("name value" pairs) if {[winfo exists $w] || $w eq ""} { set arrsaved [array get my::ttdata] set optvals [::tooltip4::my::CGet {*}$args] lassign $optvals forced geo index ttag set optvals [lrange $optvals 4 end] set my::ttdata(optvals,$w) [dict set optvals -text $text] set my::ttdata(on,$w) [expr {[string length $text]}] set my::ttdata(global,$w) no if {$text ne ""} { if {$forced || $geo ne ""} {::tooltip4::my::Show $w $text yes $geo $optvals} if {$geo ne ""} { array set my::ttdata $arrsaved ;# balloon popup } else { set tags [bindtags $w] if {[lsearch -exact $tags "Tooltip$w"] == -1} { bindtags $w [linsert $tags end "Tooltip$w"] } bind Tooltip$w <Any-Leave> [list ::tooltip4::hide $w] bind Tooltip$w <Any-KeyPress> [list ::tooltip4::hide $w] bind Tooltip$w <Any-Button> [list ::tooltip4::hide $w] if {$index>-1} { set my::ttdata($w,$index) $text set my::ttdata(LASTMITEM) "" bind Menu <<MenuSelect>> [list + ::tooltip4::my::MenuTip $w %W $optvals] } elseif {$ttag ne ""} { set ::tooltip4::my::ttdata($w,$ttag) "$text" $w tag bind $ttag <Enter> [list + ::tooltip4::my::TagTip $w $ttag $optvals] foreach event {Leave KeyPress Button} { $w tag bind $ttag <Any-$event> [list + ::tooltip4::my::TagTip $w] } } else { bind Tooltip$w <Enter> [list ::tooltip4::my::Show %W $text no $geo $optvals] } } } } }
Updates tooltips' settings according to the global settings.
| widget's path (if omitted, updates all widgets' tooltips); optional, default "" |
proc ::tooltip4::update {{w {}}} { # Updates tooltips' settings according to the global settings. # w - widget's path (if omitted, updates all widgets' tooltips) if {$w eq ""} { foreach k [array names my::ttdata -glob on,*] { set w [lindex [split $k ,] 1] set my::ttdata(global,$w) yes } } else { set my::ttdata(global,$w) yes } }
The ::tooltip4::my
namespace contains procedures for the "internal" usage by tooltip4 package.
All of them are upper-cased, in contrast with the UI procedures of tooltip4
namespace.
Gets options' values, using local (args) and global (ttdata) settings.
| local settings ("name value" pairs) |
Returns the full list of settings ("name value" pairs, "name" without "-") in which -force and -geometry option values go first.
proc ::tooltip4::my::CGet {args} { # Gets options' values, using local (args) and global (ttdata) settings. # args - local settings ("name value" pairs) # Returns the full list of settings ("name value" pairs, "name" without "-") in which -force and -geometry option values go first. variable ttdata set saved [array get ttdata] set res [::tooltip4::configure {*}$args] lappend res {*}[::tooltip4::cget] array set ttdata $saved return $res }
Fades/unfades the tooltip's window.
| the tooltip's window |
| interval for 'after' |
| interval for fading |
| counter of intervals |
| if equal to "Un", unfades the tooltip |
| value of -alpha option |
| coordinates (+X+Y) of tooltip |
| flag "show the window" |
proc ::tooltip4::my::Fade {w aint fint icount Un alpha geo show} { # Fades/unfades the tooltip's window. # w - the tooltip's window # aint - interval for 'after' # fint - interval for fading # icount - counter of intervals # Un - if equal to "Un", unfades the tooltip # alpha - value of -alpha option # geo - coordinates (+X+Y) of tooltip # show - flag "show the window" # See also: FadeNext, UnFadeNext update if {[winfo exists $w]} { after idle [list after $aint [list ::tooltip4::my::${Un}FadeNext $w $aint $fint $icount $alpha $geo $show]] } }
A step to fade the tooltip's window.
| the tooltip's window |
| interval for 'after' |
| interval for fading |
| counter of intervals |
| value of -alpha option |
| coordinates (+X+Y) of tooltip |
| flag "show the window" |
proc ::tooltip4::my::FadeNext {w aint fint icount alpha geo show} { # A step to fade the tooltip's window. # w - the tooltip's window # aint - interval for 'after' # fint - interval for fading # icount - counter of intervals # alpha - value of -alpha option # geo - coordinates (+X+Y) of tooltip # show - flag "show the window" # See also: Fade incr icount -1 if {$show} { ShowWindow $w $geo set show 0 } if {$icount<0} { set al [expr {min($alpha,($fint+$icount*1.5)/$fint)}] if {$al>0} { if {[catch {wm attributes $w -alpha $al}]} {set al 0} } if {$al<=0 || ![winfo exists $w]} { catch {destroy $w} return } } Fade $w $aint $fint $icount {} $alpha $geo $show }
Shows a menu's tooltip.
| the menu's path |
| the menu's path (incl. tearoff menu) |
| settings of tooltip |
proc ::tooltip4::my::MenuTip {w wt optvals} { # Shows a menu's tooltip. # w - the menu's path # wt - the menu's path (incl. tearoff menu) # optvals - settings of tooltip variable ttdata set index [$wt index active] set mit "$w/$index" if {[info exists ttdata($w,$index)] && ([::tooltip4::hide $w] || ![info exists ttdata(LASTMITEM)] || $ttdata(LASTMITEM) ne $mit)} { set text $ttdata($w,$index) after $ttdata(fade) [list ::tooltip4::my::Show $w $text yes {} $optvals] } set ttdata(LASTMITEM) $mit }
Creates and shows the tooltip's window.
| the parent widget's path |
| the tooltip text |
| if true, re-displays the existing tooltip |
| being +X+Y, sets the tooltip coordinates |
| settings ("option value" pairs) |
proc ::tooltip4::my::Show {w text force geo optvals} { # Creates and shows the tooltip's window. # w - the parent widget's path # text - the tooltip text # force - if true, re-displays the existing tooltip # geo - being +X+Y, sets the tooltip coordinates # optvals - settings ("option value" pairs) variable ttdata if {$w ne "" && ![winfo exists $w]} return set win $w.$ttdata(wttip) set px [winfo pointerx .] set py [winfo pointery .] if {$ttdata(global,$w)} { array set data [::tooltip4::cget] } else { array set data $optvals } if {!$force && $geo eq "" && [winfo class $w] ne "Menu" && ([winfo exists $win] || ![info exists ttdata(on,$w)] || !$ttdata(on,$w) || ![string match $w [winfo containing $px $py]])} { return } ::tooltip4::hide $w if {![string length [string trim $text]] || !$ttdata(on) || !$data(-on)} return lappend ttdata(REGISTERED) $w foreach wold [lrange $ttdata(REGISTERED) 0 end-1] {::tooltip4::hide $wold} toplevel $win -bg $data(-bg) -class Tooltip$w catch {wm withdraw $win} wm overrideredirect $win 1 wm attributes $win -topmost 1 pack [label $win.label -text $text -justify left -relief solid -bd $data(-bd) -bg $data(-bg) -fg $data(-fg) -font $data(-font) -padx $data(-padx) -pady $data(-pady)] -padx $data(-padding) -pady $data(-padding) # defeat rare artifact by passing mouse over a tooltip to destroy it bindtags $win "Tooltip$win" bind $win <Any-Enter> [list ::tooltip4::hide $w] bind Tooltip$win <Any-Enter> [list ::tooltip4::hide $w] bind Tooltip$win <Any-Button> [list ::tooltip4::hide $w] set aint 20 set fint [expr {int($data(-fade)/$aint)}] set icount [expr {int($data(-per10)/$aint*[string length $text]/10.0)}] if {$icount} { if {$geo eq ""} { catch {wm attributes $win -alpha $data(-alpha)} } else { ::tooltip4::my::Fade $win $aint [expr {round(1.0*$data(-pause)/$aint)}] 0 Un $data(-alpha) $geo 1 } after $data(-pause) [list ::tooltip4::my::Fade $win $aint $fint $icount {} $data(-alpha) $geo 1] } else { # just showing, no fading after $data(-pause) [list ::tooltip4::my::ShowWindow $win $geo] } array unset data }
Shows a window of tooltip.
| the tooltip's window |
| being +X+Y, sets the tooltip coordinates |
proc ::tooltip4::my::ShowWindow {win geo} { # Shows a window of tooltip. # win - the tooltip's window # geo - being +X+Y, sets the tooltip coordinates if {![winfo exists $win]} return set w [winfo parent $win] set px [winfo pointerx .] set py [winfo pointery .] set width [winfo reqwidth $win.label] set height [winfo reqheight $win.label] set ady 0 if {[catch {set wheight [winfo height $w]}]} { set wheight 0 } else { for {set i 0} {$i<$wheight} {incr i} { ;# find the widget's bottom incr py incr ady if {![string match $w [winfo containing $px $py]]} break } } if {$geo eq ""} { set x [expr {max(1,$px - round($width / 2.0))}] set y [expr {$py + 16 - $ady}] } else { lassign [split $geo +] -> x y set x [expr [string map "W $width" $x]] ;# W to shift horizontally set y [expr [string map "H $height" $y]] ;# H to shift vertically set py [expr {$y-16}] } # check for edges of screen incl. decors set scrw [winfo screenwidth .] set scrh [winfo screenheight .] if {($x + $width) > $scrw} {set x [expr {$scrw - $width - 1}]} if {($y + $height) > ($scrh-36)} {set y [expr {$py - $wheight - $height}]} wm geometry $win [join "$width x $height + $x + $y" {}] catch {wm deiconify $win ; raise $win} }
Shows a text tag's tooltip.
| the text's path |
| the tag's name; optional, default "" |
| settings of tooltip; optional, default "" |
proc ::tooltip4::my::TagTip {w {tag {}} {optvals {}}} { # Shows a text tag's tooltip. # w - the text's path # tag - the tag's name # optvals - settings of tooltip variable ttdata if {$tag eq ""} {set text ""} {set text $ttdata($w,$tag)} ::tooltip4::my::Show $w $text yes {} $optvals }
A step to unfade the tooltip's window.
| the tooltip's window |
| interval for 'after' |
| interval for fading |
| counter of intervals |
| value of -alpha option |
| coordinates (+X+Y) of tooltip |
| not used (here just for compliance with Fade) |
proc ::tooltip4::my::UnFadeNext {w aint fint icount alpha geo show} { # A step to unfade the tooltip's window. # w - the tooltip's window # aint - interval for 'after' # fint - interval for fading # icount - counter of intervals # alpha - value of -alpha option # geo - coordinates (+X+Y) of tooltip # show - not used (here just for compliance with Fade) # See also: Fade incr icount set al [expr {min($alpha,$icount*1.5/$fint)}] if {$al<$alpha && [catch {wm attributes $w -alpha $al}]} {set al 1} if {$show} { ShowWindow $w $geo set show 0 } if {[winfo exists $w] && $al<$alpha} { Fade $w $aint $fint $icount Un $alpha $geo 0 } }