Hyperlinks on a canvas

Lars H, 4 May 2007: I have a program displaying some diagrams in a canvas widget, and now I want to put some hyperlinks in that canvas as well. (These hyperlinks would basically cause a particular detail in the diagram to be displayed in greater detail, as there are many levels of abstraction in the data being displayed.) However, I find it rather difficult to get the proper behaviour in a canvas.

As a long-time Mac user, I find it obvious that a hyperlink should behave as follows:

  1. When the mouse pointer is on the hyperlink, it should change shape (typically to a pointing hand).
  2. When the mouse button is pressed, the hyperlink should be highlighted.
  3. Only if the mouse button is then released over the hyperlink will the action be triggered.

I haven't found this spelt out specifically for hyperlinks anywhere (though I haven't searched much either), but it can be deduced from general rules on how the mouse should behave [L1 ], and it is also what I see in all browsers I've checked (both Web and non-Web). The catch is that this seems rather hard to implement in Tk.

What I think should work is to do the following:

  • Every hyperlink is an embedded window item, probably a label.

This is necessary since the only mechanism Tk provides for changing the cursor is the window option -cursor.

  • The highlighting is done by explicitly changing colour on the item (-foreground, -background, or both).
  • Explicit bindings are needed for highlighting on (ButtonPress) and highlighting off (Leave).

This feels very roundabout (even though it is still probably easier than most C APIs would be), probably too complicated for the rather specialised program that it would be in.

What made me curious is that I noticed that a slightly different behaviour is much easier to support under Tk:

  1. When the mouse pointer is on the hyperlink, the hyperlink should be highlighted (-activeforeground or -activebackground).
  2. When the mouse button is pressed, the action is taken.

All of this can be achieved with ordinary text items in the canvas, since these support both bindings and the fancy -active... options. First time I ever saw any use for them, but then most things in Tk seem to have dozens of options I've never used...

Still, this seems almost too good a fit to be accidental. Perhaps some knowledgable person could tell me if the second behaviour is what one finds in X, as in that case this would be yet another way in which Tk is showing its deep X roots, despite aiming to be a cross-platform GUI toolkit.

LV When I use Firefox on Windows XP, what I see is this.

  • Mouse changes shape when it hovers over an HREF (hyperlink referencE)
  • When I mouse down, a box is drawn around the link
  • When I release the mouse button with the cursor still over the link with the box drawn around it, the hyperlink is activated.

On SPARC Solaris Mozilla, I see pretty much the same thing. However, different pages can modify some of that behavior, and I suspect different browsers can implement things differently. You might look at tkhtml, hyperhelp, a little hypertext system, a minimal hypertext help system as well, to see what they do.

Lars H: Thanks for cross-platform info, and the tips. A little hypertext system handles the cursor issue without embedded windows as follows:

       $w.t tag bind link <Enter> "$w.t config -cursor hand2"
       $w.t tag bind link <Leave> "$w.t config -cursor {}"

It does however activate on ButtonPress.

Lars H, update 14 May 2007: I've now implemented this -- reconfiguring the cursor made it easier than I thought. The actual code setting all of it up is just

 proc hyper_references {c} {
    $c bind reference <Enter> [list $c configure -cursor hand2]
    $c bind reference <Leave> [list $c configure -cursor {}]
    $c bind reference <ButtonPress-1> [list\
      $c itemconfigure current -fill red]
    $c bind reference <B1-Leave> "
       [list $c configure -cursor {}]
       [list $c itemconfigure current -fill blue]
    "
    $c bind reference <ButtonRelease-1> [list hyper_jump $c red]
 }

Highlighed links (items with tag "reference") are red, normal links are blue. The -fill colour is used to keep track of whether we're over the link where the mouse was pressed or not, so no helper variable is needed, and moreover is state info that should be visible to the user. The hyper_jump procedure checks whether it is released over a highlighted hyperlink.

 proc hyper_jump {c highlight} {
    if {[$c itemcget current -fill] ne $highlight} then {return}
    # Now do the actual jump
    ...
 }