UnixWorld Online: Tutorial November 1994
An Introduction to Tcl and Tk
Tcl with its X Window toolkit adds command scripts and user interfaces to both standalone tools and applications
By Brent Welch
The Tcl (Tool Command Language) has gained a lot of recognition as a new scripting language and as an embeddable interpreter that is easy to add to your applications. As a scripting language, Tcl (pronounced ``tickle'') fills the niche also occupied by various Unix shell languages such as the Bourne shell, the C shell, and Perl. By using Tcl or these other shell languages, you can glue together existing Unix applications into a tool that is customized for your particular needs. What helps to distinguish Tcl are extensions not found in other shells, for example, an easy-to-use X window system toolkit.
The core Tcl language is quite simple. There are a number of predefined commands that provide basic programming capabilities such as variables, control flow, procedures, and error handling. There are also a set of predefined commands that provide access to Unix facilities, such as accessing the file system and running other Unix programs. There is just a small amount of syntax you need to know.
Adding a Tcl interpreter to your application provides even more flexibility to your users and the system integrators who use your application. Users can write short Tcl scripts that customize your application to their liking. System integrators can exercise sophisticated control over your application, for example, by bundling it with a set of Tcl-aware applications that all work together in concert.
Perhaps the real power of Tcl comes from the large and growing number of extensions that are available for it. A Tcl extension is a set of Tcl commands that are implemented in C and packaged into a library. The programmer can create a supershell that combines several extensions together to create a platform for rapidly constructing applications by scripting them in Tcl.
The most important extension is Tk, a toolkit for the X window system. Using a Tcl/Tk shell (called
wish), programmers can create a graphical user interface at the same time they glue together their customized tool. Tk provides a much higher-level interface when compared to other toolkits such as Motif or the Windowing Korn Shell. It takes just a few Tcl commands to define user interface widgets and compose them into a working interface.Tcl Basics
The syntax for a Tcl command is simple. The first word is the name of a command. The command name and the remaining arguments are separated by spaces. The command is terminated by a newline or a semicolon. The arguments are passed to the command implementation without interpretation, except for the substitutions described below.
The basic structure is augmented with two mechanisms: grouping, used to get arguments that contain whitespace; and substitution, a macro-like facility used with variables and nested command invocations. There are two ways to group things. Grouping with curly braces,
{ }, prevents substitutions from occurring on the things inside them, while grouping with double quotes," ", allows substitutions. Finally, there are also some backslash sequences that can be used to quote special characters and to obtain characters by specifying their character code.The first line in Listing 1A defines a Tcl variable,
name, as having the valueBrent Welch. The curly braces used to group the value into one argument are discarded before thesetcommand is invoked. The second command outputs a string to the standard output. In this case double quotes are used so that$namewill be substituted with the value of variablename. The substitution and grouping occurs beforeputsis invoked. Thus the basic function of the Tcl interpreter is to parse a command to do groupings, then substitutions, and finally invoke the command with the resulting arguments.The interpreter also does command substitution to allow for nested commands. For example, suppose we want to get the current date. We can do this by running the Unix
datecommand, as shown in Listing 1B.The Tcl interpreter treats the string between the matching square brackets as another Tcl command. It postpones processing of the current command, invokes the nested command, and then replaces the square brackets and everything between them with the value returned by the nested command. In this case, the Tcl
execcommand returns whatever the program has written to its standard output, which is something likeMon Aug 8 17:01:53 PDT 1994.There is an implicit grouping done too, so there is no need to group the results of the
datecommand even though it contains spaces. In other words, it is not necessary to quote a nested command, as in. set d "[exec date]"A rule of thumb to help you in more complex cases is to remember that grouping decisions are made before substitutions. Grouping of characters into arguments is determined by whitespace, curly braces, and double quotes. Substitutions are triggered by the dollar sign for variable substitutions and square brackets for command substitutions.
A Tcl/Tk Front End to
pingFor our first extended example we will write a user interface to the Unix
pingcommand, which sends a network packet to a host and waits for an answer. It reports the time taken or a failure if the host does not respond. Our first version of the script (see Listing 2A) will be a bit limited, but we will address those limitations in the second example.The first line of the script causes it to be interpreted by
wish, the Tcl/Tk shell. Of course, on your systemwishmight be installed in an alternate location. The-fis required for historical reasons. Thewishshell was originally designed just to test the Tk toolkit. Due to limitations of the Unixexec()system call, this line must be fewer than 32 characters in length, including the#!and the-f, so be careful if you install a private copy ofwishin some deeply nested directory. You will get confusing ``Command not found'' errors when running the script.This script creates several Tk widgets, one each on lines 3, 6, 7, 10, 11, 12, and 15. The example uses
buttons, which have an associated Tcl command; alabel, which is a read-only text widget; anentry, which is a one-line text-entry widget;frames, which are container widgets; and atextwidget, which is a general-purpose multiline text widget.If you examine Tcl commands that create the widgets you will see a common form. The command name indicates what kind of widget is being created. The first argument is the name of the widget. The remaining arguments are pairs of attributes and values for the widgets. Tk widgets have a lot of attributes so that you can control most of their appearance and behavior, but in most cases you only need to specify a few attributes and can leave the rest of the attributes in their default settings.
Tk uses a naming convention for its widgets that reflects their position in the hierarchy of windows. The main window of an application is named simply ``.'', and other widgets have a path name of components separated by periods. This pattern is analogous to the way Unix files are named, where ``/'' is the name of the root directory, and files have path names with components separated by slashes.
In this example there are three widgets that are children of the main window:
.buttons,.f, and.log. Thepackcommands on lines 4, 10, and 16 arrange these widgets in a vertical stack inside the main window by specifying the-side toppacking parameters.There are two buttons that are children of the
.buttonsframe:.buttons.quitand.buttons.ping. These are arranged in a horizontal stack by thepackcommand on line 8 by specifying-side right(see Figure 1). A similar thing is done on lines 10 through 13 with the.fframe that is used to hold the label,.f.l, and the entry,.f.host. Line 10 contains two Tcl commands just to remind you that the semicolon character functions as a command terminator.I have found horizontal and vertical stacking of widgets within frames to be the most trouble-free way of using the Tk packer. There are other features of the packer that I have to skip for this introduction.
GUI Made Simple
The interface consists of the Quit and Ping buttons, the entry widget used to name the host, and the text widget used to log the output.
The way that the Quit button functions is fairly straightforward. When the user clicks on it, the associated Tcl command,
exit, is invoked, which causes the program,wish, to terminate. Note that there is nothing at the end of the script to tell it to keep going, either. This action is implicit in the behavior ofwish, which reads a Tcl script to configure the interface and then goes into an event loop processing window events.The Ping button invokes the Ping command, as shown on lines 18 through 24. Let's digress and talk about Tcl syntax again. Lines 18 through 24 form a single Tcl command because of the way grouping with curly braces works. It groups characters, including newlines and semicolons, until a matching brace is found. Grouping with double quotes works the same way, except that there is no nesting.
The Tcl
proccommand (line 18) takes three arguments: the procedure name, an argument list, and a command body. In this case the argument list is empty, so we use curly braces to group no characters to form the empty list. The curly braces around the procedure body are placed carefully. The opening brace at the end of line 18 causes the interpreter to keep scanning characters until it gets to the matching brace, in spite of the embedded newlines. These characters together form the third argument toproc. At this time they are uninterpreted because of the curly braces used to group them.The commands within Ping are interpreted later when the Ping command is invoked. At that time the newlines in the command body serve as command terminators and break the body up into several commands. Finally, note that
hostnameis a local variable inside Ping and that it is not defined elsewhere, even after Ping has been invoked.The Ping command does three things. First, it gets the current value of the entry widget with the
.f.host getcommand. The name of the widget is a Tcl command that operates on the widget. The.logcommand is used to insert the results of Ping into the text widget. The Unixpingcommand is run under the protection of the Tclcatchcommand in case it raises an error. Tclexecwill raise an error if the command is not found or if the command writes to standard error.The first argument to
catchis a Tcl command, and the second is the name of a variable in which to place the result (or error message). Thecatchcommand returns 1 if an error was raised, or 0, but we are ignoring the return value in this case. I recommend using braces to group the Tcl command argument tocatchbecause it will call the full Tcl evaluator on that argument, at which time any substitutions will occur. If you use double quotes, you will get two rounds of substitutions, which can cause unexpected results.There are some details not covered here, like the exact meanings of all the attributes for the widgets and the details of using text and entry widgets. There are Unix manual pages for each of the Tcl and Tk commands that describe all the details.
Improving our Front End
The main problem with this example is that we'd like to run
pingin its mode that continuously queries the host, and add a Stop button. To do so, we will need to split the example into two scripts that communicate using the Tksendcommand. One script will be the control panel, the other will be a helper script that runspingand sends the output to the control panel for logging. Listing 2B shows the helper script.Line 3 tells the window manager to unmap the window. The main window isn't needed by the helper, but we need to use
wishto use thesendcommand.Lines 4 and 5 access the command-line arguments. The
lindexcommand is used to index into a list. Theargvvariable is the list of command-line arguments for the script. The first argument is the name of the host toping, and the second argument is the name of the Tcl interpreter with which to communicate.Line 6 opens a pipeline for reading. That is, the Unix command
ping -s $hostnameis forked (with$hostnamesuitably replaced), and the output of that program is available to the script by reading from an I/O stream. Line 7 uses thegetscommand to do the reading. Thegetscommand puts the next line of input into a variable,line, and returns the number of characters read, not counting the newline that is discarded.Line 8 uses the
sendcommand to invoke a Tcl command, namelyInsert $line, in another interpreter. In this case we use thelistcommand to properly construct the command for us, taking into account any special characters that might be in the line. The$lineis substituted beforelistis invoked and well before the command gets sent. Thelistcommand formats its arguments in such a way that they will survive reparsing by the remote interpreter. Thus thesendcommand gets two arguments, the name of the other interpreter, and a safely packaged Tcl command.We can leave the control panel script alone, except for changing the Ping procedure and adding two more procedures. The
Insertprocedure inserts into the log, and theStopprocedure stops the helper script. The changes to Ping and the two new procedures are shown in Listing 2C.On line 21 the helper script is run. It is passed two arguments: the host name and the result of a command that returns the name of the Tcl interpreter. This name identifies the interpreter to others so that they can send it Tcl commands. The helper script is run in the background, and
execreturns its process ID.You can dynamically change any Tk widget attribute that you could specify when you created the widget. On lines 22 and 33 the behavior and appearance of
.button.pingis changed. The button is alternately a Ping button and a Stop button (see Figure 2).The Ping and Stop procedures need to communicate the process ID of the helper script, done with the global variable
pid. By default, variables inside procedures are local. Theglobalcommand makes them visible in the global scope.The
Insertprocedure is there for convenience. We could have arranged forpinghelperto send all the commands insideInsert, but that would be awkward. As the script evolves, theInsertprocedure will probably prove useful in other situations, too.Where to Get Tcl/Tk
Tcl and Tk, and a host of extensions, are available freely over the Internet. The current archive site for Tcl is
ftp://www.sunlabs.com/pub/tcl. Tcl and Tk are distributed under a University of California at Berkeley copyright that allows for use in commercial products with no license fee. There is a newsgroup,comp.lang.tcl, for discussion of Tcl and its applications. Tcl and the Tk toolkit were created by Professor John Ousterhout while he was at U.C. Berkeley. I recommend his book, Tcl and the Tk Toolkit, published by Addison-Wesley.
Copyright © 1995, 1996 The McGraw-Hill Companies, Inc. All Rights Reserved.
Edited by Becca Thomas / Online Editor / UnixWorld Online / editor@unixworld.com Last Modified: Tuesday, 24-Sep-96 07:48:14 PDT