5.12 Example: Help Popups

In the following we want to look at a small example which provides for a generic interactive help popup window. The idea is that if the mouse pointer stays over a widget for some time without pressing a mouse button, a small help text is displayed. The help text should disappear if the mouse pointer leaves the screen area covered by the widget.

We will build a procedure AttachHelp such that help texts are enabled by application of the procedure to a widget and a help text. We proceed in three steps, the first is to create a function to create a toplevel widget that displays the help text, the second is a listener class (that is, a subclass of Tk.listener), and the last step is the definition of AttachHelp itself.

5.12.1 Displaying Help

The procedure MakePopup shown in Figure 5.12 takes a widget and the help text as its argument and returns a function to create a toplevel widget containing the text at a position relative to the widget on the screen.

<Definition of MakePopup>=
fun {MakePopup Parent Text}
   fun {$}
      [X Y H]={Map [rootx rooty height]
               fun {$ WI}
                  {Tk.returnInt winfo(WI Parent)}
      W={New Tk.toplevel tkInit(withdraw:true bg:black)}
      M={New Tk.message
         tkInit(parent:W text:Text bg:khaki aspect:400)}
      {Tk.batch [wm(overrideredirect W true)
                 wm(geometry W '+'#X+10#'+'#Y+H)
                 pack(M padx:2 pady:2)
                 wm(deiconify W)]}

Figure 5.12: Creating a help window.

The returned function creates a toplevel widget in withdrawn state and configures the toplevel widget such that it:

  1. is not equipped with a frame from the window manager. This is done by using the window manager command overrideredirect: the window manager is advised to not ``redirect'' the toplevel widget into a frame.

  2. appears at a position relative to X and Y coordinates of the widget parent, which done by the geometry window manager command.

  3. appears on the screen by deiconifying it.

5.12.2 The Listener Class

The listener class HelpListener is shown in Figure 5.13. The method init initializes an instance of this class by creating a procedure for creation of the popup widget.

<Definition of HelpListener>=
class HelpListener from Tk.listener 
      cancel: unit 
      popup:  unit 
   meth init(parent:P text:T)
      popup := {MakePopup P T}
   meth enter 
      cancel := C
      thread A={Alarm 1000} in 
         {WaitOr C A}
         if {IsDet A} then W={@popup} in 
            {Wait C} {W tkClose}
   meth leave 

Figure 5.13: The listener class HelpListener.

When the mouse pointer enters the parent widget, the method enter gets executed. This method stores a new variable C in the attribute cancel which serves as flag whether the help popup must be closed. The newly created thread waits until either one second has elapsed (A gets bound after 1000 milliseconds) or the widget has been left (C gets bound). Then possibly the widget for the help text is created, which gets closed when the parent widget is left. Note that if both A and C happen to be bound at the same time, the popup will be created and then closed immediately.

The leave method signals that the help popup must be closed by binding the variable stored in cancel.

5.12.3 AttachHelp

The definition of AttachHelp is shown in Figure 5.14. It creates a listener and creates event bindings that are served by that listener.

<Definition of MakePopup> 
<Definition of HelpListener> 
   proc {AttachHelp Widget Text}
      L={New HelpListener init(parent:Widget text:Text)}
      {Widget tkBind(event:'<Enter>'  action:L#enter append:true)}
      {Widget tkBind(event:'<Leave>'  action:L#leave append:true)}
      {Widget tkBind(event:'<Button>' action:L#leave append:true)}

Figure 5.14.

5.12.4 Using Help Popups

A small example that shows how to use help popups is shown in Figure 5.15.

Bs={Map ['Okay'   # 'Do nothing meaningful.' 
         'Cancel' # 'Do nothing at all.' 
         'Quit'   # 'Close the window.']
    fun {$ Text # Help}
       B={New Tk.button tkInit(parent:W text:Text)}
       {AttachHelp B Help} B
{Tk.send pack(b(Bs) side:left padx:2#m pady:2#m)}

Figure 5.15: Demo of the HelpPopup class.

Christian Schulte
Version 1.4.0 (20080702)