- 30 -

Tcl and Tk

by Rick McMullin

IN THIS CHAPTER

This chapter introduces the Tcl programming language and its most popular extension, Tk. This chapter covers the following topics:

By the end of this chapter, you should understand what Tcl and Tk are, and also how to write simple applications using Tcl and Tk.

What Is Tcl?

Tcl stands for Tool Command Language. (It is pronounced "tickle.") It is a scripting language similar to the shell scripting languages introduced in Chapter 13, "Shell Programming." Tcl can be used to quickly write text-based application programs.

Tcl was developed by John Ousterhout, then of the University of California at Berkeley. Tcl is an interpreted language and therefore has the usual advantages and disadvantages of all interpreted languages. The key disadvantage of interpreted languages is that they execute much slower than compiled languages. The biggest advantage of interpreted languages is that developing applications using them is usually much faster than using compiled languages. This is because you don't have to wait for code to compile and can see any changes you make to the code almost instantly.

Tcl has a core set of built-in functions that provide the basic features of its programming language. The true power of Tcl, however, is that it is easily extendible. Application programmers can add functions to Tcl and can even imbed the Tcl function library directly into their applications. This gives programmers the power to include an interpretive scripting language directly in their own application without having to do any of the work of developing the language. This means that you can provide users of your application with all the commands that exist within Tcl and also any that you create and add to the Tcl library.

Invoking Tcl commands is done by starting up the Tcl shell, called tclsh (or on some systems, tcl). Once you have started tclsh, you can type Tcl commands directly into it. Straying slightly from the "hello world" example that you find in almost every introductory language text, the following example shows you how to write Hello there instead to the screen:

puts stdout "Hello there"

This command contains three separate words. The first word in the command is the actual command name, puts. The puts command is an abbreviation for put string; it simply writes something to the device that is specified in the second word of the command. In this case the second word tells puts to write to the standard output device, which is typically the screen. The third word in the puts command is "Hello there". The quotation marks tell Tcl to interpret everything contained within them as a single word.


NOTE: The default output device is stdout (standard output, usually the screen), so if you intend to write something to stdout using the puts command, the second argument is optional.

Even though this is a very simple example, it illustrates the basic command syntax of the Tcl language. There are obviously many more commands contained within Tcl, but the basic syntax of all Tcl commands is the same:

command parameter1 parameter2 ...

The command can be any of the built-in Tcl commands, or it can be a user-defined extension to the Tcl command set in the form of a Tcl procedure. In either case, the fundamental syntax remains unchanged.

What Is Tk?

Tk, which was also developed by Ousterhout, is a graphical user interface extension to Tcl. Tk is based on the X Window system and allows application developers to develop X Window-based applications much faster than they could using other X Window toolkits, such as Motif or OPEN LOOK.

Like Tcl, Tk also has a shell that enables you to enter commands to be interpreted. The Tk shell is a superset of the Tcl command shell. This means that anything you can do in the Tcl command shell you can also do in the Tk command shell. The big difference between the two is that the Tk command shell was designed to enable you to build X Window front ends to your applications.

The Tk command shell is called wish, which stands for windowing shell. You must be running X Window when you invoke wish. This is because when wish is invoked, it brings up a window to display the results of any of the graphical commands it interprets. When you invoke wish, a window should appear on your screen.

Now that you have seen what the Tk environment looks like, let's try enhancing the earlier "Hello there" example by displaying Hello there in a button in the wish window. To accomplish this, you must first ensure that wish has been started. This is easily done by typing the following command into an Xterm window:

wish

This command brings up the wish window and also executes the Tk interpreter in the Xterm window. You can now type Tcl or Tk commands directly in the Xterm window. These are the commands necessary to print Hello there in a button in the wish window:

button .b -text "Hello there." -command exit

pack .b

Notice how the syntax of the command on the first line is essentially the same as the syntax of the puts command. It contains the command name followed by a number of arguments. The first argument is the name you are giving to the new button. The rest of the arguments passed to the button command are slightly different from the arguments you saw in the Tcl version of the "Hello there" example. These arguments each consist of two parts. The first part tells Tk what the argument name is, and the second part tells Tk the value of the argument.

The second argument has the name text, and the value of the argument is the string you want to display in the button. The third argument has the name command and is used to specify the command that you want to execute when that button is pushed. In this example, you do not really want anything to happen if the button is pushed, so you just tell wish to exit from the current script.

The button command created a button widget that you called .b. To get the button to show up in the wish window, you must tell Tk to display the button. This is done by the pack command.

In this example, the pack command has only one argument: the name of the button that you created in the first command. When the pack command is executed, a button with the string Hello there displayed in it appears in the wish window.

Two things about this example are worth discussing in more detail. The first is why you called the button .b instead of b, bob, or button1. The significance is not the actual text in the button name (this in fact could be bob or button1), but the period (.) preceding the name of the button.

The period notation is used to represent the widget hierarchy. Each widget is contained in another widget. The root widget, or the highest level widget, is contained in the wish window and is called . (this is analogous to the Linux directory structure, in which each directory has an owner or a parent directory and the root or highest level directory is named /). Each time you create a new widget, you must tell Tk which widget the new widget should be contained in. In the "Hello there" example, the container specified for the button widget was ., the root widget.

The second item of interest is the resizing of the wish window that occurs after you enter the pack command. The wish window shrinks down to a size that is just large enough to hold the button you created. Tk causes the wish window to default to a size just large enough to hold whatever it has in it. Many commands can be used to change this behavior and customize how things are displayed on the screen. You will see some of these commands later in this chapter.

The Tcl Language

Now that you have seen examples of both Tcl and Tk in action, it is appropriate to take a step back and look at the underlying Tcl language in more detail. Tcl contains a rich set of programming commands that support all the features found in most high-level languages. This section discusses many of these features and gives examples that explain how to use them.

Tcl Variables and Variable Substitution

Like the UNIX shell programming languages, Tcl supports the concept of variables. Variables are temporary storage places used to hold information that will be needed by a program at some later point in time. In Tcl, variable names can consist of any combination of printable characters.

Typically, variable names are meaningful names that describe the information being stored in them. For example, a variable that is being used to hold the monthly sales of a product might have one of the following names:

Monthly_sales

"Monthly sales"


NOTE: Quotation marks cause Tcl to ignore the whitespace characters (spaces and tabs) in the variable name and treat it as one word. This is discussed in the "Quotes" section of this chapter.

The value that is placed into a variable can also be any combination of printable characters. Possible values for the Monthly_sales variable are

"40,000"

40000

"refer to table 3"

The Tcl set command is used to assign values to variables. The set command can pass either one or two arguments. When two arguments are passed to the set command, the first one is treated as the variable name and the second is the value to assign to that variable.

When the set command is used with only one argument, Tcl expects the argument to be the name of a variable, and the set command returns the value of that variable. The following command assigns the value of 40000 to the variable Monthlysales and then echoes the value to the screen:

set Monthlysales 40000

To print the value of the Monthlysales variable to the screen, you would type

set Monthlysales

All values that are assigned to variables are stored as character strings. If you defined a variable to be equal to the integer 40, as in the following command

set num 40

the value 40 would be represented as the character string 40, not as an integer.

So far you have seen how to set variables and how to display their values to the screen, but you have not seen how they are used with commands other than the set command. To use the value of a variable in another command, you must precede the variable name with an unquoted dollar sign ($). This tells Tcl to expect a variable name and to substitute the value of that variable for the variable name. The following example shows a simple use of variable substitution:

set Monthlysales 40000

expr $Monthlysales * 12

The first command assigns the value of 40000 to the variable Monthlysales. The expr command is used to perform mathematical evaluations of expressions. In this case it takes the value of the variable Monthlysales and multiplies it by 12.

Tcl Command Substitution

Command substitution provides a way of substituting the result of a Tcl command (or commands) into an argument of another command. The syntax for command substitution is to include the commands that are being substituted in square brackets, as follows:

set Monthlysales 40000

set Yearlyforecast [ expr Monthlysales * 12 ]

The first command once again sets the variable Monthlysales to the value of 40000. The second command makes use of command substitution to set the value of Yearlyforecast equal to the result of the command in the square braces.

In this example the substitute consisted of only one command. Tcl allows the substitute to consist of any valid Tcl script, meaning that it can contain any number of Tcl commands.

Quotes

Often you want to use commands containing special characters that you don't want Tcl to interpret. By quoting these characters, you hide the special characters from the Tcl interpreter.

Three kinds of quoting can be used in Tcl scripts. The first is quoting with double quotation marks (""). This kind of quoting is used to hide whitespace characters and command separators from the Tcl interpreter.

Whenever you have two or more words that you want Tcl to treat as a single word, you can do so by surrounding the words with quotation marks. A good example of this type of quoting is when you want to create variable names that contain more than one word, or you want to assign a value that contains more than one word to a variable, as follows:

set "Monthly sales" 40000


set Heading1 "Description of item"

The second kind of quoting uses the backslash character (\). This type of quoting can hide any single character from the interpreter. This form of quoting is most commonly used to hide special characters, such as $, from the Tcl interpreter. The following example illustrates the need for backslash quoting:

set Header1 "The cost is \$3.50"

In this example the Header1 variable is being assigned the value The cost is $3.50. The quotation marks are necessary to hide the fact that there are four separate words contained in the character string. The backslash in this command tells the Tcl interpreter to treat the $ as a regular character instead of the variable substitution character. If the backslash was not used in the command, the interpreter would attempt to substitute the variable named 3.50 into the command. This would result in an error, because there is no variable with that name defined.

The third type of quoting available in Tcl uses curly braces ({}). This quoting is more powerful than quoting using quotation marks or backslashes. Quoting using braces hides not only whitespace and command separators from the Tcl interpreter but also any other kind of special character. This type of quoting can be used to eliminate the need for backslash quoting in character strings. The example used for backslash quoting could be written using brace quotation as follows:

set Header1 {The cost is $3.50}

The most important use of curly brace quoting is to defer the evaluation of special characters. This means that special characters are not processed immediately by the Tcl interpreter but are instead passed to a command that processes the special characters on its own. An example of when deferred evaluation is used is in the while command:

set count 0

while {$count < 3} {

      puts "count equals $count"

      set count [expr $count + 1]

}

The while command has to evaluate both of its arguments each time it iterates through the loop. It is therefore necessary for the interpreter to ignore the special characters in both of these arguments and leave the evaluation of these characters up to the while command.

Now that you have all the language basics out of the way, you can move on to some of the more advanced Tcl commands.

The if Command

The if command, just like in other languages, evaluates an expression and, based on the results of the expression, executes a set of commands. This is the syntax of the if command:

if {expr} {commands}

The if command expects two arguments. The first argument is an expression that is used to determine whether to execute the commands contained in the second argument. The expression argument is typically an expression that evaluates to either True or False. For example:

$i < 10

$num = 2


NOTE: Tcl treats any expression that evaluates to zero to be False and any expression that evaluates to a non-zero value to be True.

Expressions such as the following, although valid, do not make much sense in the context of an if command:

$i + $b

10 * 3

The second argument to the if command is a Tcl script, which can contain any number of Tcl commands. This script is executed if the expression contained in the first argument evaluates to True.

The if commands can have one or more elseif commands and one else command associated with them. The syntax for these commands is shown here:

if {expr} {

      commands }

elseif {expr} {

      commands }

elseif {expr} {

      commands }

else {

      commands }

The commands associated with the first if or elseif whose expression evaluates to True are executed. If none of these expressions evaluate to True, the commands associated with the else command are executed.


WARNING: The open curly brace must occur on the same line as the word that precedes it. This is because new lines are treated as command separators. If you entered an if command where the if {expr} portion of the command appeared on one line and the rest was on the next line, it would be treated as two separate commands.

The for Command

The for command in Tcl provides a way of implementing for loops. Tcl for loops are very similar to for loops in other languages, such as C. The for command expects four arguments. The first argument is a script that is used to initialize the counter. The second argument is an expression that is evaluated each time through the loop to determine whether to continue. The third argument is used to define the increment to be used on the counter. The fourth argument is the set of commands to be executed each time through the loop.

for { set i 0} {$i < 10} {incr i 1} {

      puts [expr 2 * $i]

}

The preceding loop executes ten times. The counter i is initially set to 0. The for loop executes while i is less than 10, and the value of i is increased by 1 each time through the loop. The command that is executed each time through the loop is the puts command. This evaluates 2 x i each time through the loop and prints the result to the screen. The output that results from running this command is listed here:

0 

2 

4 

6 

8 

10 

12 

14 

16 

18

The while Command

The while command is used to implement while loops in Tcl. while loops are very similar to for loops. The only real difference between them is that the for loop provides more enhanced features for controlling entrance and exit criteria for the loop. The syntax for the while loop is shown in the following example:

set i 0

while {$i < 10} {

      puts [expr 2 * $i]

      set i [expr $i + 1]

}

This while loop performs the same function as the example that was presented in the section describing the for loop. It calculates 2 x i each time through the loop and prints the result to the screen. Notice that in this example you have to handle incrementing the counter yourself. With the for loop, the counter incrementing was taken care of by the for command.

The switch Command

The switch command provides the same function as an if statement that has multiple elseif clauses associated with it. The switch command compares a value (this value is usually stored in a variable) with any number of patterns, and if it finds a match it executes the Tcl code associated with the matching pattern.

switch $thing {

      car {puts "thing is a car"}

      truck {puts "thing is a truck"}

      default {puts "I don't know what this thing is"}

}


NOTE: The Tcl switch command is equivalent to the case statement found in Pascal and some other languages.

This switch command compares the value that is stored in the thing variable (which must be set prior to these statements, of course) with the string car and the string truck to see if it matches either of them. If the value of the thing variable is equal to car, then thing is a car is displayed on the screen. If the value of the thing variable is equal to truck, then thing is a truck is displayed on the screen. If neither of these cases are true, the default clause is executed and I don't know what this thing is displays on the screen.


TIP: Whenever you need to check to see if a variable is equal to one of a number of values, you should use a switch command instead of an if command with multiple elseif clauses. This makes your code much easier to read and understand.

Comments

It is always a good idea to include comments in any Tcl code you write--or code you write in any other language, for that matter. This becomes especially important if any of the following situations is possible:

Chances are that at least one of these situations will come up with Tcl code you have written.

Comments cannot be placed in the middle of a command. They must occur between commands. The pound sign (#) is used to inform Tcl to expect a comment.

# This is a valid comment

set a 1 ;   # This is a valid comment

set a 1           # This is an invalid comment

The third comment shown here is invalid because it occurs in the middle of a command.


NOTE: Recall that Tcl interprets everything up to a newline character or a semicolon to be part of the command.

The Tk Language Extensions

Earlier in this chapter, a simple example of Tk displayed Hello there in a button in the wish window. Tk is much more powerful than that example showed. Along with the button widget are many other widgets provided by Tk. These include menus, scrollbars, and list boxes. This section gives you an overview of some of the other Tk widgets and gives short examples explaining how these widgets can be used.

Frames

Frame widgets are containers for other widgets. They do not have any interesting behavior like the other Tk widgets. The only visible properties of frame widgets that you can set are their color and their border appearance. You can give three different border appearances to a frame widget: flat, raised, and sunken. You can experiment with the different frame widgets to see how they look.

The flat border frame widget is not too exciting. It looks exactly the same as the default wish window (because the default border appearance is flat).

Buttons

Button widgets are used to get specific input from a user. A button can be turned on or activated by the user of a Tk program by moving the mouse pointer over the button and then pressing the left mouse button. Tk provides the following three kinds of button widgets:

The button widget is used to initiate some specific actions. The button usually has a name such as "Load file" that describes the action that results if you press the button.

Check button widgets are used to allow users of a program to turn program options on or off. When the check button is shaded the program option is on, and when the check button is not shaded the program option is off.

Radio buttons are similar to check buttons except that they are defined in groups, where only one member of a group of radio buttons is allowed to be on at one time. This means that if one radio button in a group of radio buttons is on, none of the other radio buttons in that group can be turned on. When the radio button is shaded it is on, and when the radio button is not shaded it is off.

Menus and Menu Buttons

Menu widgets are used to implement pull-down menus, cascading menus, and pop-up menus. A menu is a top-level widget that contains a set of menu entries that have values or commands associated with them. Five kinds of entries can be used in menus:

The main difference between the menu entries and the button widgets is that the button widgets can exist by themselves, but the menu entries must exist within the context of a menu widget.

Menu button widgets are similar to button widgets. The only real difference between the two is that when menu buttons are invoked they bring up menus instead of executing Tcl scripts as button widgets would. The menu button name usually describes the types of menu entries contained in the menu that the menu button activates. This means that you should find menu entries that perform some kind of file operations contained within the File menu.

You can activate a menu by moving the mouse pointer to the menu button widget and pressing the left mouse button. This activates the menu associated with the menu button and displays the menu entries that are contained in that menu to the screen. You can now move the mouse pointer down through the list of menu entries and select the one you want.

The File menu contains two command entries (the Open entry and Quit entry), one cascade entry (the Save As entry), and one separator entry. The menu that comes up as a result of clicking the mouse pointer on the Save As cascade entry contains three command entries: the Text entry, the Ver 1 file entry, and the Ver 2 file entry.

List Boxes

The list box widget enables users of a Tk application to select items from a list of one or more items. If the number of items to be displayed in the list box is larger than the number of lines in the list box, you can attach scrollbars to make the extra items accessible.

Scrollbars

Scrollbar widgets are used to control what is displayed in other widgets. Scrollbar widgets are attached to other widgets to allow users to scroll up and down through the information contained in the widget. You typically put scrollbars on any widget that is designed to contain an arbitrary number of lines of information (such as a list box) or on widgets that contain more lines of information than the widget can display, given its size.

Summary

This chapter started off by introducing Tcl and the Tk tool kit and describing the uses of both. Although this chapter contained a lot of information, it barely scratched the surface of the programming tools provided by Tcl and the Tk tool kit.

Tcl has many more programming features than were described in this book. Some of the most notable are arrays, lists, and procedures.

Not all of the Tk widgets were described here, either. Some of the widgets that were not described are canvasses, scales, labels, messages, and textedit widgets.

Tk is just one example of an extension to Tcl. There are many other extensions available that extend the behavior of Tcl in different ways. Some of these extensions are listed here:

If you would like to learn more about Tcl and Tk, a good place to start is the manual pages for Tcl, Tk, and any of the specific commands you want information about. There are also a few books available that are devoted to Tcl and Tk programming.