John is creator of the Tcl language, author of Tcl and the Tk Toolkit, and a professor at the University of California at Berkeley. He can be contacted at ouster@allspice.cs.berkeley.edu. This article is excerpted from Tcl and the Tk Toolkit, by John K. Ousterhout. Copyright (C) 1994 by Addison-Wesley Publishing Company. Reprinted by permission of Addison-Wesley.
Tcl, short for "tool command language" (and pronounced "tickle"), is a simple scripting language for controlling and extending applications. Tcl provides generic programming facilities, such as variables, loops, and procedures, useful for a variety of applications. Furthermore, Tcl is an embeddable command language. Its interpreter is a library of C procedures that can easily be incorporated into applications, and each application can extend the core Tcl features with additional commands for that application.
The core Tcl facilities can be extended with Tk, a toolkit for the X Window System. Tk includes commands for building user interfaces so that you can construct Motif-like UIs by writing Tcl scripts instead of C code. Like Tcl, Tk is implemented as a library of C procedures, so it can be used in many different applications. Individual applications can also extend the base Tk features with new UI widgets and geometry managers written in C.
One benefit of Tcl and Tk is that they lend themselves to rapid development. Many GUI applications can be written entirely as Tcl scripts, using a windowing shell called "wish" that allows you to program at a higher level than you would in C/C++. Compared to toolkits in which you program in C (such as Motif), there is much less code to write and certainly much less to learn.
Another reason Tcl and Tk development is rapid is that Tcl is an interpreted language. When you use a Tcl application, you can generate and execute new scripts on the fly without recompiling or restarting the application. This allows you to test out new ideas and fix bugs rapidly. Interpreted code executes more slowly than compiled C code, but today's workstations are surprisingly fast. For example, you can execute scripts with hundreds of Tcl commands on each movement of the mouse with no perceptible delay. In rare cases where performance becomes an issue, you can reimplement the performance-critical parts of your Tcl scripts in C.
Tcl also makes it easy for applications to have their own powerful scripting languages. To create a new application, you simply implement a few new Tcl commands that provide the basic features of your application. Then you can link your new commands with the Tcl library to produce a full-function scripting language that includes both the commands provided by Tcl (the "Tcl core") and those that you wrote, as in Figure 1(a). For example, an application for reading electronic bulletin boards (BBSs) might contain C code that implements one to query a BBS for new messages and another Tcl command to retrieve a given message. Once these commands exist, Tcl scripts can be written to cycle through the new messages from all the BBSs and display them one at a time, keep a record in disk files of which messages have been read and which haven't, or search one or more BBSs for messages on a particular topic.
Furthermore, Tcl is an excellent glue language. A Tcl application can include many different library packages, each of which provides an interesting set of Tcl commands, as in Figure 1(b). Tk is just one example library package; many others exist. Tcl scripts for such applications can include commands from any of the packages.
Tcl scripts can also be used as a communication mechanism to allow different applications to work together. For example, any windowing application based on Tk can send a Tcl script to any other Tk application to be executed there. Among other things, this makes multimedia effects much more accessible: Once audio and video applications have been built with Tk, any Tk application can issue record and play commands to them. Indeed, an audio extension for Tcl called "Ak" provides Tcl commands for file playback, recording, telephone control, and synchronization. In addition, spreadsheets can update themselves from database applications, UI editors can modify the appearance and behavior of live applications as they run, and so on. In fact, Tcl's use of a common, interpreted language for communication between applications is more powerful and flexible than static approaches such as Microsoft's OLE and Sun Microsystems' ToolTalk.
To invoke Tcl scripts, you must run a Tcl application. The Tcl system includes a simple Tcl shell application called "tclsh," on which the examples presented here are based. To run the application, simply type tclsh to your shell and the program will start up in interactive mode, reading Tcl commands from the keyboard and passing them to the Tcl interpreter for evaluation. Entering tclsh expr 2 + 2, for example, prints the result (4) and prompts you for another command.
This simple example illustrates several Tcl features. First, Tcl commands are similar in form to shell commands, each consisting of one or more command words separated by spaces or tabs. This example has four words: expr, 2, +, and 2. The first word of each command, or "name," selects a C procedure in the application to carry out the command's function. The other words are "arguments" passed to the C procedure. expr, a core command provided by the Tcl library that exists in every Tcl application, concatenates its arguments into a single string and evaluates the string as an arithmetic expression.
Each Tcl command returns a result string. For the expr command, the result is the value of the expression. Results are always returned as strings, so expr converts its numerical result back to a string in order to return it. If a command has no meaningful result, it returns an empty string.
Commands are normally terminated by newlines, so each line that you type to tclsh becomes a separate command. Semicolons also act as command separators, just in case you want to enter multiple commands on a single line. Single commands can also span multiple lines.
The expr command supports an expression syntax similar to that in ANSI C, including the same precedence rules and most of the C operators. Example 1 provides a few examples that you could enter into tclsh. Invoking the exit command terminates the application and returns you to your shell.
Although Tcl provides a full set of programming features such as variables, loops, and procedures, it is not typically used by itself. It is intended to be used as part of applications that contain their own Tcl commands, in addition to those in the Tcl core. The application-specific extensions provide interesting primitives, and Tcl is used to assemble the primitives into useful functions. It is easier to understand Tcl's facilities if you have seen some application-specific commands to use with Tcl.
One of the most interesting extensions to Tcl is the set of windowing commands provided by the Tk toolkit. Most of the examples in this article use an application called "wish" (short for "windowing shell") which is similar to tclsh except that it includes the commands defined by Tk that allow you to create GUIs. If Tcl and Tk have been installed on your system, you can invoke wish from your shell; it will display a small empty window on your screen and then read commands from standard input. Example 2 is a simple wish script. If you type these two Tcl commands to wish, the window's appearance will change to that shown in Figure 2. If you move the pointer over the "Hello, world!" text and click mouse button 1 (usually the left-most button), the window will disappear and wish will exit.
Several things about this example are worth noting. First, the example contains two commands, button and pack, both of which are implemented by Tk. Although these commands do not look like the expr command, they have the same basic structure as all Tcl commands: one or more words, separated by white space. The button command contains six words, and pack two.
The fourth word of the button command is enclosed in double quotes. This allows the word to include white-space characters; without the quotes, "Hello," and "world!" would be separate words. The double quotes are not part of the word itself; they are removed by the Tcl interpreter before the command is executed.
The word structure doesn't matter for the expr command since expr concatenates all its arguments. For button and pack (and most other Tcl commands), however, the word structure is important. The button command expects its first argument to be the name of a new window to create. Subsequent arguments must come in pairs, where the first argument of each pair is the name of a configuration option and the second is a value for that option. Thus if the double quotes were omitted, the value of the --text option would be "Hello," and "world!" would be treated as the name of a separate configuration option. Since no option is defined with the name "world!", the command would return an error.
The basic building block for a GUI in Tk is a "widget"--a window with a particular appearance and behavior (the terms "widget" and "window" are used synonymously in Tk). Widgets are divided into classes such as buttons, menus, and scroll bars. All the widgets in the same class have the same general appearance and behavior. For example, all button widgets display a text string or bitmap and execute a Tcl command when invoked with the mouse.
Widgets are organized hierarchically in Tk, with names that reflect their positions in the hierarchy. The "main widget," which appears on the screen when you start wish, has the name ".". The name .b, for instance, refers to a child b of the main widget. Widget names in Tk are like filenames in UNIX except that they use a period as a separator character instead of a slash. Thus, .a.b.c refers to a widget that is a child of widget .a.b, which is a child of .a, which is a child of the main widget.
Tk provides one "class command" for each class of widgets, which you invoke to create widgets of that class. For example, the button command creates button widgets. All of the class commands have the same form: The first argument is the name of a new widget to create, and additional arguments specify configuration options. Different widget classes support different sets of options. Widgets typically have many options (about 20 different options are defined for buttons, for example), and default values are provided for the options that you don't specify. When a class command like button is invoked, it creates a new widget with the given name and configures it as specified by the options.
The command in Example 2 specifies two options: --text, a string to display in the button, and --command, a Tcl script to execute when the user invokes the button. In Example 2, the --command option is exit. Other button options are listed in Table 1.
The pack command causes the button widget to appear on the screen. Creating a widget does not automatically cause it to be displayed. Independent entities called "geometry managers" are responsible for computing the size and location of widgets and making them appear on the screen. The pack command in Example 2 asks a geometry manager called the "packer" to manage .b. The command asks that .b fill the entire area of its parent window; if the parent has more space than needed by its child, the parent is shrunk so that it is just large enough to hold the child. Thus when you type the pack command, the main window shrinks from its original size to the size in which it appears in Figure 2.
You can also place commands into script files and invoke the script files just like shell scripts. To do this for Example 2, place the text in Example 3 in a file named "hello." This script is the same as Example 2 except for the first line. As far as wish is concerned, this line is a comment, but if you make the file executable (type chmod +x hello to your shell, for example) you can invoke the file directly by typing hello to your shell. The system will then invoke wish, passing it the file as a script to interpret; wish will display the same window and wait for you to interact with it. In this case, you will not be able to type commands interactively to wish; all you can do is click on the button. (Note: This script will work only if wish is installed in /usr/local/bin. If wish has been installed elsewhere, you will need to change the first line to reflect its location on your system. Some systems will misbehave in confusing ways if the first line of the script file is longer than 32 characters, so beware if the full pathname of the wish binary is longer than 27 characters.)
In practice, Tk application users rarely type Tcl commands; they interact with the applications using the mouse and keyboard in ways normal for graphical applications. Tcl works behind the scenes. The hello script behaves just the same as an application coded in C with a toolkit such as Motif and compiled into a binary executable file.
During debugging, however, it is common for application developers to type Tcl commands interactively. For example, you could test the hello script by starting wish interactively. Type wish to your shell instead of hello. Then enter the Tcl command source hello where source is a Tcl command that takes a filename as an argument. It reads the file and evaluates it as a Tcl script. This generates the same UI as if you had invoked hello directly from your shell, but you can now type Tcl commands interactively. For example, you could edit the script file to change the --command option to Example 4(a), then interactively type the commands in Example 4(b) to wish without restarting the program. The first command in Example 4(b) deletes the existing button, and the second recreates the button with the new --command option. When you click on the button, the puts command prints a message on standard output before wish exits.
Tcl allows you to store values in variables and use those values in commands. For instance, you could enter the script in Example 5 into either tclsh or wish. Example 5(a) assigns the value 44 to variable a and returns the variable's value. In Example 5(b), the $ causes Tcl to perform "variable substitution," replacing the dollar sign and the variable name following it with the value of the variable, so that the actual argument received by expr is 44*4. Variables need not be declared in Tcl; they are created automatically when set. Variable values are stored as strings, and arbitrary string values of any length are allowed. Of course, in this example an error will occur in expr if the value of a doesn't make sense as an integer or real number (try other values and see what happens).
Tcl also provides command substitution, which allows you to use the result of one command in an argument to another. Square brackets invoke command substitution: Everything inside the brackets is evaluated as a separate Tcl script, the result of which is substituted into the word in place of the bracketed command. In Example 5(c), the second argument of the second set command will be 176.
The final form of substitution in Tcl is backslash substitution, which allows you to use various special characters in a command, as in Example 5(d). The first command sets variable a to the string $a (the characters \$ are replaced with a dollar sign and no variable substitution occurs). The second command sets variable newline to hold a string consisting of the newline character (the characters \n are replaced with a newline character).
Example 6 uses variables and substitutions along with some simple control structures to create a Tcl procedure called "power," which raises a base to an integer power. If you enter Example 6(a) into wish or tclsh, or if you enter them into a file and then source the file, a new command power will become available. The command takes two arguments, a number and an integer power, and its result is the number raised to the power; see Example 6(b). This example uses Tcl braces which are like double quotes in that they can be placed around a word that contains embedded spaces. However, braces are different from double quotes in two respects. First, braces nest. The last word of the proc command starts after the open brace on the first line and contains everything up to the close brace on the last line. The Tcl interpreter removes the outer braces and passes everything between them, including several nested pairs of braces, to proc as an argument. The second difference between braces and double quotes is that substitutions cannot occur inside braces. All of the characters between the braces are passed verbatim to proc without any special processing.
The proc command takes three arguments: the name of a procedure, a list of argument names separated by white space, and the body of the procedure, which is a Tcl script. proc enters the procedure name into the Tcl interpreter as a new command. Whenever the command is invoked, the body of the procedure is evaluated. While the procedure body is executing, it can access its arguments as variables: base will hold the first argument to power and p will hold the second.
The body of the power procedure contains the Tcl commands set, while, and return. The while command does most of the procedure's work. It takes two arguments: an expression $p>0 and a body, which is another Tcl script. The while command evaluates its expression argument; if the result is nonzero, it evaluates the body as a Tcl script. It repeats this process until eventually the expression evaluates to zero. In Example 6, the body of the while command multiplies the result value by base and then decrements p. When p reaches zero, the result contains the desired power of base.
The return command causes the procedure to exit with the value of variable result as the procedure's result. If it is omitted, the return value of the procedure will be the result of the last command in the procedure's body. In the case of power, this would be the result of while, which is always an empty string.
The use of braces in this example is crucial. The single most difficult issue in writing Tcl scripts is managing substitutions: making them happen when you want them and preventing them when you don't. The body of the procedure must be enclosed in braces because you don't want variable and command substitutions to occur at the time the body is passed to proc as an argument; you want the substitutions to occur later, when the body is evaluated as a Tcl script. The body of the while command is enclosed in braces for the same reason: You want the substitutions to be performed each time the body is evaluated, rather than once, while parsing the while command. Braces are also needed in the {$p>0} argument to while. Without them, the value of variable p would be substituted when parsing the while command; the expression would have a constant value and while would loop forever.
Although Tcl doesn't require it, for readability I'm using a syntax where the open brace for an argument that is a Tcl script appears at the end of one line, the script follows on successive lines indented, and the close brace is on a line by itself after the script. Arguments that are scripts are subject to the same syntax rules as any other arguments; in fact, the Tcl interpreter doesn't even know that an argument is a script at the time it parses it. One consequence is that the open brace must be on the same line as the preceding portion of the command. If the open brace is moved to a line by itself, the newline before the open brace will terminate the command.
The variables in a procedure are normally local to that procedure and will not be visible outside it. In Example 6, the local variables include the arguments base and p as well as the variable result. A fresh set of local variables is created for each call to a procedure (arguments are passed by copying their values), and when a procedure returns, its local variables are deleted. Variables named outside any procedure are "global"--they last forever unless explicitly deleted.
As a programming language, Tcl is defined quite differently than most other languages. In most languages, a grammar defines the entire language. In Example 7(a), for instance, the grammar for C defines the structure of this C statement in terms of the reserved word while, an expression, and a substatement to execute repeatedly until the expression evaluates to 0. The C grammar defines both the overall structure of the while statement and the internal structure of its expression and substatement.
In Tcl, no fixed grammar explains the entire language. Instead, it is defined by an interpreter that parses single Tcl commands, plus a collection of procedures that execute them. The interpreter and its substitution rules are fixed, but new commands can be defined at any time and existing commands can be replaced. Features such as control flow, procedures, and expressions are implemented as commands; they are not understood directly by the Tcl interpreter. For example, the Tcl command in Example 7(b) is equivalent to the C while loop in Example 7(a).
When the command in Example 7(b) is evaluated, the Tcl interpreter knows only that it has three words, the first of which is a command name. The Tcl interpreter has no idea that the first argument to while is an expression and the second is a Tcl script. Once the command has been parsed, the Tcl interpreter passes the words of the command to while, which treats its first argument as an expression and the second as a Tcl script. If the expression evaluates to nonzero, then while passes its second argument back to the Tcl interpreter for evaluation. At this point, the interpreter treats the contents of the argument as a script (that is, it performs command and variable substitutions and invokes the expr and set commands).
As far as the Tcl interpreter is concerned, the set command in Example 7(c) is identical to while except that it has a different command name. Therefore, the interpreter handles the two commands identically, except that it invokes a different procedure to execute set. The set command treats its first argument as a variable name and its second as a new value for that variable, so it will set a variable with the name $p>0.
The most common mistake made by new Tcl users is trying to understand Tcl scripts in terms of a grammar; this leads them to expect much more sophisticated behavior from the interpreter than actually exists. For example, a C programmer using Tcl for the first time might think that the first pair of braces in the while command serves a different purpose than the second pair. In reality, there is no difference. In each case, the Tcl interpreter passes the characters between the braces to the command without performing any substitutions.
Thus the entire Tcl "language" consists of about a half-dozen simple rules for parsing arguments and performing substitutions. At the same time, Tcl is powerful enough to allow a rich set of structures such as loops and procedures to be built as ordinary commands. Applications can extend Tcl not just with new commands but also with new control structures.
A binding causes a certain Tcl script to be evaluated whenever a particular event occurs in a particular window. The --command option for buttons is an example of a simple binding implemented by a particular widget class. Tk also includes a more general mechanism that can be used to extend the behavior of widgets in nearly arbitrary ways.
When copied into a file and invoked from your shell, the script in Example 8 will produce a screen display like that in Figure 3. The display has two entry widgets in which you can click with the mouse and type numbers. If you press the Return key in either of the entries, the result will appear on the right side of the window. You can compute different results by modifying either the base or the power and then pressing Return again.
This application consists of five widgets: two entries and three labels. Entries are widgets that display one-line text strings that you can edit interactively. The two entries, .base and .power are used for entering the numbers. Each entry is configured with a --width of 6 (large enough to display about six digits) and a --relief of "sunken" (which gives the entry a depressed appearance). The --textvariable option for each entry specifies the name of a global variable to hold the entry's text; any changes you make in the entry will be reflected in the variable and vice versa.
Two of the labels, .label1 and .label2, hold decorative text; the third, .result, holds the result of the power computation. The --textvariable' option for .result causes it to display whatever string is in the global variable result and to update itself whenever the variable changes. In contrast, .label1 and .label2 display constant strings.
The pack command arranges the five widgets in a row from left to right. The command occupies two lines in the script; the backslash at the end of the first line is a line-continuation character, which causes the newline to be treated as a space. The --side option means that each widget is placed at the left side of the remaining space in the main widget: first .base is placed at the left edge of the main widget, then .label1 is placed at the left side of the space not occupied by .base, and so on. The --padx and --pady options make the display more attractive by arranging for one millimeter of extra space on the left and right sides of each widget, plus two millimeters of extra space above and below it. The m suffix specifies millimeters; you could also use c for centimeters, i for inches, p for points, or no suffix for pixels.
The bind commands connect the UI to the power procedure. Each bind command has three arguments: the name of a widget, an event specification, and a Tcl script to invoke when the given event occurs in the given widget. <Return> specifies an event consisting of the user pressing the Return key on the keyboard. Other useful event specifiers are listed in Table 2.
The scripts for the bindings invoke power, passing it the values in the two entries and storing the result in the result variable so that it will be displayed in the .result widget. These bindings extend the generic, built-in behavior of the entries (editing text strings) with application-specific behavior (computing a value based on two entries and displaying that value in a third widget).
The script for a binding has access to several pieces of information about the event, such as the location of the pointer when the event occurred. For example, if you start up wish interactively, type the command bind.<Any-Motion> {puts "pointer at %x,%y"}'>, and move the pointer over the window, each time the pointer moves, a message will be printed on standard output giving its new location. When the pointer motion event occurs, Tk scans the script for % sequences and replaces them with information about the event before passing the script to Tcl for evaluation. %x is replaced with the pointer's x-coordinate, and %y is replaced with the pointer's y-coordinate.
Normally, Tcl executes each command by invoking a C procedure in the application to carry out its function. This is different from a shell program such as sh, where each command is executed in a separate subprocess. However, Tcl also allows you to create subprocesses using the exec command; see Example 9.
The exec command treats its arguments much like the words of a shell command line. In Example 9(a), exec creates a new process to run the grep program and passes it #include and tk.h as arguments, just as if you had typed grep #include tk.h to your shell. The grep program searches file tk.h for lines that contain the string #include and prints those lines on its standard output. However, exec arranges for standard output from the subprocess to be piped back to Tcl. exec waits for the process to exit, then returns all of the standard output as its result. With this mechanism you can execute subprocesses and use their output in Tcl scripts. exec also supports input and output redirection using standard shell notation such as <, <<, and >, pipelines with |, and background processes with &.
Example 9(b) creates a simple UI for saving and reinvoking commonly used shell commands. If you type the script into a file named "redo" and invoke it, the script initially creates an interface with a single entry widget. You can type a shell command such as ls into the entry, as shown in Figure 4(a). If you press Return, the command gets executed as if you had typed it to the shell from which you invoked redo; the <@ and >@ arguments to exec cause the standard input and output files for the command to be the same as those for wish. Furthermore, the script creates a new button widget that displays the command, and you can reinvoke the command later by clicking on the button; see Figure 4(b). As you type more commands, more buttons appear, up to a limit of five remembered commands, as in Figure 4(c).
The most interesting part of the redo script is in the bind command. The binding for <Return> must execute the command, which is stored in the cmd variable, and create a new button widget. First it creates the widget. The button widgets have names like .b1, .b2, and so on, where the number comes from the variable id which starts at 0 and increments before each new button is created. The notation .b$id generates a widget name by concatenating .b with the value of id. Before creating a new widget, the script checks to see if there are already five saved commands; if so, the oldest existing button is deleted. The notation .b[expr $id --5] produces the name of the oldest button by subtracting five from the number of the new button and concatenating it with .b. The --command option for the new button invokes exec and redirects standard input and output for the subprocess(es) to wish's standard input and standard output, which are the same as those of the shell from which wish was invoked. This causes output from the subprocesses to appear in the shell's window instead of being returned to wish.
The command pack .b$id --fill x makes the new button appear at the bottom of the window. The option --fill x improves the appearance by stretching the button horizontally so that it fills the width of the window even if the text doesn't really need that much space.
The last two commands of the binding script are called "widget commands." Whenever a new widget is created, a new Tcl command with the same name is created, and you can invoke this command to communicate with the widget. The first argument to a widget command selects one of several operations, and additional arguments are used as parameters for that operation. In the redo script, the first widget command causes the button widget to invoke its --command option, just as if you had clicked the mouse button on it. The second widget command clears the entry widget in preparation for a new command to be typed.
Each class of widget supports a different set of operations in its widget commands, but many of the operations are similar from widget to widget. For example, every widget class supports a configure widget command that can be used to modify any of the configuration options for the widget. If you run the redo script interactively, you can type in the command in Example 10(a) to change the background of the entry widget to yellow or the command in Example 10(b) to change the color of the text in button .b1 to brown and then cause the button to flash.
One of the most important things about Tcl and Tk is that they make every aspect of an application accessible and modifiable at run time. For example, the redo script modifies its own interface on the fly. In addition, Tk provides commands that you can use to query the structure of the widget hierarchy, and you can use configure widget commands to query and modify the configuration options of individual widgets.
There's much more to Tcl and Tk than I've presented here. Also available, for instance, is Extended Tcl (TclX), a library package that augments the built-in Tcl commands by providing access to POSIX functions and system calls, file scanning similar to awk, keyed lists, online help, and so on. Tcl Distributed Programming (Tcl-DP) is a collection of Tcl commands that simplify the development of distributed programs, while XF is an interactive interface builder that was actually written in Tcl. For additional information on these and other Tcl, refer to my book, Tcl and the Tk Toolkit.
Tcl and Tk contain many other facilities not discussed in this article, including:
Arrays and lists: arrays, for efficiently storing key value pairs; and lists, for managing aggregates of data.
Control structures for controlling the flow of execution, such as eval, for, foreach, and switch.
String manipulation: measuring their length, regular-expression pattern matching and substitution, and format conversion.
File access: You can read and write files from Tcl scripts and retrieve directory information and file attributes, such as length and creation time.
Widgets: menus, scroll bars, a drawing widget called a "canvas," and a text widget for achieving hypertext effects.
Access to X facilities: access to all major facilities in the X Window System, such as commands for communicating with the window manager, retrieving the selection, and managing the input focus.
Interapplication communication: a send command can be used to issue arbitrary Tcl/Tk scripts to other Tk-based applications.
C interfaces: C-library procedures to define new Tcl commands in C and a library for creating new widget classes and geometry managers in C.
--J.K.O.
(a) Enter: expr 3 << 2
Returned value: 12
(b) Enter: expr 14.1*6
Returned value: 84.6
(c) Enter: expr (3 > 4) ||
(6 <= 7)
Returned value: 1
button .b -text "Hello, world!" -
command exit
pack .bFigure 1 Simple TCL application consisting of the Tcl interpreter plus a few application-specific commands; (b) complex application which includes the commands defined by Tk plus additional commands defined by other packages. Figure 2 Tcl "hello world" program.
Option Description
--background Background color for the button, such as blue.
--foreground Color of the text in the button, such as black.
--font Name of the font to use for the button, such as
*--times--medium--r--normal*120* for a 12-point
Times Roman font.
#!/usr/local/bin/wish -f
button .b -text "Hello, world!" -
command exit
pack .b
(a) -command "puts Good-bye!; exit"
(b) destroy .b
source hello
(a) Enter: set a 44
Returned value: 44
(b) Enter: expr $a*4
Returned value: 176
(c) Enter: set a 44
set b [expr $a*4]
Returned value: 176
(d) set x \$a
set newline \n
(a) proc power {base p} {
set result 1
while {$p0} {
set result [expr $result*$base]
set p [expr $p-1]
}
return $result
(b) Enter: power 2 6
Returned value: 64
Enter: power 1.15 5
Returned value: 2.01136
(a) while (p>0) {
result *= base;
p -= 1;
}
(b) while {$p>0} {
set result [expr $result*$base]
set p [expr $p-1]
}
(c) set {$p>0} {
set result [expr $result*$base]
set p [expr $p-1]
}
#!/usr/local/bin/wish -f
proc power {base p} {
set result 1
while {$p>0} {
set result [expr $result*$base]
set p [expr $p-1]
}
return $result
}
entry .base -width 6 -relief sunken -textvariable base
label .label1 -text "to the power"
entry .power -width 6 -relief sunken -textvariable power
label .label2 -text "is"
label .result -textvariable result
pack .base .label1 .power .label2 .result -side left \
-padx 1m -pady 2m
bind .base <Return> {set result [power $base $power]}
bind .power <Return> {set result [power $base $power]}Figure 3 A GUI that computes powers of a base.
(a)
Enter: exec grep #include tk.h
Returned value: #include <tcl.h>
#include <X11/Xlib.h>
#include <stddef.h>
(b)
#!/usr/local/bin/wish -f
set id 0
entry .entry -width 30 -relief sunken -textvariable cmd
pack .entry -padx 1m -pady 1m
bind .entry <Return> {
set id [expr $id + 1]
if {$id > 5} {
destroy .b[expr $id - 5]
}
button .b$id -command "exec <@stdin >@stdout $cmd" \
-text $cmd
pack .b$id -fill x
.b$id invoke
.entry delete 0 end
}
Event Specifier Description
<Button1> Mouse button 1 is pressed.
<1> Shorthand for <Button1>.
<ButtonRelease1> Mouse button 1 is released.
<Double-Button1> Double-click on mouse button 1.
<Keya> The "a" key is pressed.
<Motion> Pointer motion with no buttons or modifier keys
pressed.
<B1-Motion> Point motion with button 1 pressed.
<Any-Motion> Pointer motion with any (or no) button or modifier
keys pressed.
Figure 4 The redo application.
(a) .entry configure -background yellow
(b) .b1 configure -foreground brown
.b1 flash>
Copyright © 1994, Dr. Dobb's Journal