the tclsh spot
Adding Hypertext Links and Image Display to htmlview.tcl![]()
by Clif Flynt
Clif Flynt has been a professional programmer for almost twenty
years, and a Tcl advocate for the past four. He consults on Tcl/Tk and
Internet applications.
This article will describe how to add hypertext links and image display to the htmlview.tcl package. Along the way, we'll briefly examine some of Tcl's support for large-scale projects (the namespace and package commands), binding events to actions, accessing the Web with the http package, and the image object. You can find more details in my book, Tcl/Tk for Real Programmers; Steve Ball's Web Tcl Complete; and Mike Doyle and Hattie Schroeder's Interactive Web Applications in Tcl/Tk. Two of the Tcl commands that simplify large-scale programming projects are the namespace and package commands. These commands support two software-engineering concepts that help construct easily maintained, modular code. The namespace command hides a set of commands and data in a private area where they won't interact with other code. The package command groups a set of procedures (possibly in several source files) into a single entity that can be accessed by name and optionally selected by revision number. A namespace is similar in some respects to a C++ or Java class. Like a class, the items within a namespace may be either procedures or data. The data hidden within a namespace is available to all members of that namespace without being visible from the global scope (unless a script specifically requests the item). Tcl namespaces do not support inheritance, but namespaces can be nested. Items within a namespace are named with a path-style naming convention, similar to the way X-11 windows or directory paths are named. The path separator for Tcl namespaces is the double colon (::). For example, an item baz within a namespace bar that's included within a namespace foo would be named as ::foo::bar::baz. A namespace is created with the namespace eval command: Syntax: namespace eval namespaceID arg ?args?
For example, this code will create a fastfood namespace, with internal variables for burgers and fries, and a burgerSeller procedure for modifying the number of burgers. By keeping the burger count inside the namespace, the customers can access a burger only by interacting with a burgerSeller.
namespace eval fastfood {
Selected components within a namespace can be made easily accessible with the namespace export and namespace import commands, or they can be accessed with the full namespace path identifier. The http package hides all of its functions within the http namespace. Since the modified htmlview package will only use the http namespace, the simplest way to access the http functions will be via their full path. For example, the command ::http::geturl evaluates the procedure geturl within the http namespace. Note that this doesn't invoke the procedure defined within the http namespace in the current namespace; it evaluates the geturl procedure within the http namespace. The package command is a librarian, similar in some respects to the UNIX ar command. It joins a bunch of related procedures so that they can be accessed with a single name. Unlike the ar command, the package command doesn't create a new file for the joined data. The package create command creates a directory file (pkgIndex.tcl) that's used to determine which files should be loaded to resolve procedure references at runtime. A Tcl script uses the package require command to declare that it will need to access a previously defined package. The script can also declare whether it requires a particular revision of this package, the latest revision, or the most recent minor revision of a particular major revision. Syntax: package require ?-exact? packageName ?versionNum?
So, with these two commands, we can look at how to use the http package. The two most-used commands in the http package are:
This script downloads and prints the contents of the Scriptics homepage:
package require http
The htmllib.tcl package has hooks to handle hypertext links. The htmllib.tcl package creates a binding on the text between an <HREF> and </HREF>. When a user clicks on that text, the procedure HMlink_callback will be invoked. Syntax: HMlink_callback win href
Adding this code to the htmllib.tcl will enable the HTML viewer to access links:
package require http
That takes care of links. How about images? Since I still don't want all images to be loaded when I read some spam by accident, I want to be able to click on a blank image and load just that image. (Cynical folks might notice that this selection mechanism lets me avoid banner ads.) When the htmllib.tcl package sees an <img . . .> tag, it evaluates the HMset_image procedure with three arguments: the name of the primary text window, the name of the window that marks the location for this image, and the URL of the image. When the image has been loaded, HMset_image will invoke HMgot_image with the location marker and the new image data. A normal browser would load the image data in HMset_image and immediately invoke HMgot_image to display it. Since we'd rather select the images we're interested in seeing, we'll bind an action to the marker label and load the image when the label is clicked. The Tcl bind command lets a script define an event that can happen to a graphic object and define a script to evaluate when that event occurs. Syntax: bind widgetName eventType script
If we define a new procedure HMimage_request to actually acquire and display the image, we can implement HMset_image like this to create a binding on the label that will invoke HMimage_request when the label is clicked. The $src variable contains the URL for the image. By calling HMgot_image with the $src variable, the htmllib.tcl package will change the text in the label from the generic image to the actual URL (making it easier for us to decide whether we want to see this image).
proc HMset_image {win handle src} {
The Tcl command for creating an image is the image command. Tcl can create either bitmap or full-color (photo) images from X11 bitmaps, GIF, or JPEG format data. Several extensions to Tcl add support for other image formats. (See Jan Nijtmans'site: <http://www.worldaccess.nl/~nijtmans/>). The Tcl image command can accept photo data as binary data in a file, or as BASE64-encoded data in a variable. Since converting binary data to BASE64 and back to binary is a bit silly, we might as well use an intermediate file to hold the binary data. Syntax: image create type ?name? ?options?
Here's the code for HMimage_request. It uses the pid command to get the task's process ID as a cheap and dirty way to make a (probably) unique file name. Once it has a name, it opens an output channel to that file and invokes http::geturl to copy the image data from the remote site into that file. Once the image has been created (the data has been read), that file can be deleted with the file delete command.
proc HMimage_request {win handle url } {
At this point, the htmlview program has most of the functionality of a real browser, with a much smaller footprint than Netscape. Actually writing a full-featured browser in Tcl, however, is not quite so trivial as this makes it look. You may want to look at the Plume browser at <http://plume.browser.org> to see an example of a fully featured Tk-based browser. A version of htmlview.tcl with support for images and hypertext links is available at <http://www.cflynt.com>.
1st August, 1999
|
![]() Last changed: 29 Nov. 1999 mc |
|