Version 1 of Hyperlink widget

Updated 2012-08-12 21:37:46 by RLE

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.