Version 5 of Hyperlink widget

Updated 2012-08-13 01:18:05 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.

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.

RLE (2012-08-12): Yes, but then you would no longer have a generic hyperlink widget. You'd have a specialized widget for a particular purpose, reducing the usefulness of the widget in general. I.e., assume that "fetchers" were built in, and clicking the hyperlink would "fetch" something. Now what? What does the widget do with the something that was fetched? The answer to that is "it depends on what the application needs to do with the thing fetched". Which means what to do when a click occurs should be the subject of a different module, not the hyperlink widget itself. The hyperlink widget should simply be a generic way to put a clickable link into a GUI. What the application does when the link is clicked is the responsibility of the command that the hyperlink widget calls to report that a click has occurred. In this way the generic hyperlink widget is useful for any of:

  • fetching a file
  • uploading a file
  • exiting the application
  • saving current work

when clicked. Or in other words it is useful for whatever the author of the application wants the click to represent.