Version 4 of Hyperlink widget

Updated 2012-08-12 22:48:21 by nagu

Moved from Tk 9.0 WishList because it was getting a bit long to remain there.

nagu - Hyperlink basic widget that includes all the functionality of <a> tag in HTML. I am not talking about the hyperlink tags inside text/canvas widgets. I should be able to create a hyperlink like creating a label widget.

RLE (2012-08-10): You mean something like this?:

$ wish
% font create Underline-Font {*}[ font actual TkDefaultFont ]              
Underline-Font
% font configure Underline-Font -underline true -size 12                   
% label .hyperlink -text "Click Me" -foreground blue -font Underline-Font
.hyperlink
% bind .hyperlink <Button-1> [ list puts "Click Me was clicked" ]
% pack .hyperlink
% # now click with mouse button one on the "hyperlink"
% Click Me was clicked

Creating a wrapper/snit-widget is left as an exercise.

nagu (2012-08-12): Yes.. thats what I meant. Thanks for the code snippet. However, it would be really nice to have a pre-built wrapped up hyperlink widget. That gives "standardized" interface to a widget that is most often needed and asked for in many discussions online. It deserves it and its a low hanging fruit to implement - IMHO.

RLE (2012-08-11): Given the trivial amount of effort needed to create this widget, creating a basic wrapper proc, or creating a snit widget that encapsulates this concept would appear to be relatively trivial.

I.e.: (very basic wrapper proc, this requires at least Tcl 8.5):

proc hyperlink { name args } {
  if { "Underline-Font" ni [ font names ] } {
    font create Underline-Font {*}[ font actual TkDefaultFont ]
    # adjust size below to your preference
    font configure Underline-Font -underline true -size 12
  }
  if { [ dict exists $args -command ] } {
    set command [ dict get $args -command ]
    dict unset args -command
  }
  # note - this forcibly overrides foreground and font options
  label $name {*}$args -foreground blue -font Underline-Font
  if { [ info exists command ] } {
    bind $name <Button-1> $command
  }
  return $name
}

And now you can do:

hyperlink .hl -command [ list puts "clicked" ] -text "Click Me"
pack .hl

To get a hyperlink widget created and mapped on screen.

nagu (2012-08-13 IST): I will also add -image option in addition to the text (underlined). Thanks again for the code snippet. We've already started implementing it. This proves the point that its a low-hanging-fruit to implement. Couple of additional points why we should pre-wrap it:

  • Helps avoid redundant implementation in every Tk application - point behind any wrapper anyway.
  • Makes life simple. I, as a not-so-technical programmer, try to avoid using bind and maintaining color of text when its clicked etc. etc.
  • Helps modernizing. That is, it helps to move away from old fashioned buttons (which people call it clunky!) to clickable text/image links.

RLE (2012-08-12): label already supports an -image option, so there is nothing to add. The only thing the wrapper really does is capture the "-command" option to create a binding, then pass everything else through to the underlying label, except that it does override the -font and -foreground options.

Using a tiny bit more code to add a missing -font and -foreground option into the $args dict you also get external control of -font and -foreground but get the defaults otherwise. I.e. (this also changes the cursor to the traditional URL hand when it is above the label widget):

proc hyperlink { name args } {

  if { "Underline-Font" ni [ font names ] } {
    font create Underline-Font {*}[ font actual TkDefaultFont ]
    # adjust size below to your preference
    font configure Underline-Font -underline true -size 12
  }

  if { [ dict exists $args -command ] } {
    set command [ dict get $args -command ]
    dict unset args -command
  }

  # add -foreground and -font, but only if they are missing
  set args [ dict merge [ dict create -foreground blue -font Underline-Font ] $args ]

  label $name {*}$args

  if { [ info exists command ] } {
    bind $name <Button-1> $command
  }

  bind $name <Enter> [ list $name configure -cursor hand2 ]
  bind $name <Leave> [ list $name configure -cursor {} ]

  return $name
}

nagu (2012-08-13 IST): Also, instead of being just a clickable text/image, it can be made a real hyperlink that accepts a -href option to take-in a URL and invokes a callback command to process the content fetched. The fetchers should be plug-ins based on the type of content (like http, file etc.). This feature will make it a real hyperlink widget.

RLE (2012-08-12): No need. Simply install a -command like this:

 -command [ list url-fetcher http://www.example.com/page/to/fetch ]

Then your "url-fetcher" proc can do whatever it wants to do with the url.

nagu (2012-08-13 IST): Thanks. Its getting better. By fetchers being plug-ins, I meant they are pre-wrapped too. Like image command having handlers pre-built for various types of images with extensible design, it will be good if we hide the details of fetching from users and Tklib or other libraries providing extended handlers for different protocols.