Introduction to Tcl

This page was originally presented as 'Introduction to Tcl/Tk', in 2002. The original format was produced with LaTeX and is still available intro_tcl.pdf


Definitions


Introduction

This white paper is intended to be an short introduction to the Tcl/Tk scripting language. An attempt was made to include the most important Tcl concepts, pitfals, and frequently used programming constructs. There are several excellent books listed in the bibliography at the end of this reference.

I would recommend the following books in order:

  1. Practical Programming in Tcl/Tk, Brent Welch (the Tcl/Tk Bible)
  2. Tcl/Tk for Real Programmers, Clif Flynt (a great Tk reference)
  3. Tcl/Tk Programmers Reference, Christopher Nelson (the manpage on steroids)

Why use Tcl/Tk?


Why not use Tcl/Tk?


Interpreter shells - tclsh

tclsh is the Tcl shell interpreter. This interpreter does not include support for graphical Tk applications. It is executed by entering:

tclsh

Scripts are typically executed by entering:

tclsh program_name.tcl

Under Windows this program is named tclsh.exe or may contain a version number such as tclsh83.exe. Scripts can also be executed by entering the following command in the tclsh interpreter:

source program_name.tcl

Interpreter shells - wish

wish is the Tcl/Tk interpreter. It supports Tcl commands as well as the graphical tool kit (Tk). It is executed by entering:

wish

Under Windows there is a program named wish.exe or may also contain a version name such as wish83.exe. Scripts can also be executed by entering:

wish program_name.tcl

Under Unix, Tcl applications can also be executed by entering in the filename at the command prompt. For this to work the Tcl filename must be referenced with an absolute path or be found in the current search path. The Tcl file must have execute privileges. The first line of the file should be:

#!/usr/bin/tclsh

Similarly for Tcl/Tk executing under the wish interpreter:

#!/usr/bin/wish

Manpage Support

The manpage (man) command is supported by the tclsh interpreter. Be aware that command not built into the tclsh interpreter will be passed to the operating system for execution, so system manpages may be displayed.

$ tclsh

A truncated example manpage follows:

% man fconfigure

fconfigure(n) Tcl Built-In Commands fconfigure(n)
_________________________________________________________________
NAME
fconfigure - Set and get options on a channel

SYNOPSIS
fconfigure channelId
fconfigure channelId name
fconfigure channelId name value ?name value ...?
_________________________________________________________________
DESCRIPTION
The fconfigure command sets and retrieves options for
channels. ChannelId identifies the channel for which to
set or query an option. If no name or value arguments are
supplied, the command returns a list containing alternat
ing option names and values for the channel. If name is
supplied but no value then the command returns the current
value of the given option. If one or more pairs of name
and value are supplied, the command sets each of the named
options to the corresponding value; in this case the
return value is an empty string.

It should also be noted that this automatic passing of non Tcl commands to the operating system can be disabled by setting the auto noexec variable.


Comments

Comments are line based in Tcl. End of line comments are allowed but a semicolon MUST be placed at the end of the interpreted code on that line.

#!/usr/bin/tclsh
# tcl is line comment based
# no need to use semicolons for line terminations
# but they are allowed
set real_years 4 # this is a malformed comment (no semicolon)
set dog_name "spot"; # semicolon is require for EOL commment
set dog_years [expr (7 * $real_years)]
puts "my dog $dog_name is $real_years"
puts "he acts $dog_years old"

Line Continuation

Line continuation is accomplished by using a backslash. Do not follow the backslash with any characters, or even any whitespace characters! The backslash escapes the next character which is intended to be the newline.

#!/usr/bin/tclsh
# the backslash escapes the new line
# dont put a space after it!
set members { \
    george \
    fred \
    jeff \
    alice \
    }
puts $members

Curly Braces

Curly braces around a string do not allow variable substitution within the string, the string is taken literally. Unmatched curly braces may cause the interpreter to wait indefinitely for more input, no errors, no warnings, no output. Curly braces count even if they are in a comment, this will cause brace mismatches that can be difficult to find.


Square Brackets

Square brackets are used for controlling the order of execution.


Substitution

Double quotes will allow substitution in the string being quoted. Curly braces will not allow substitution.

#!/usr/bin/tclsh
set years 41
set years_sub "I am $years";
set years_no_sub {I am $years};
puts "this string got substituted - weak quoting"
puts $years_sub
puts "this string did not substitute - rigid quoting"
puts $years_no_sub

Math Functions

The interpreter is told to perform math functions by using the expr command.

#!/usr/bin/tclsh
set r 2.0
set pi [expr { 4 * atan(1.0) }]
set area [expr {$pi * $r * $r}]
puts "r: $r"
puts "pi: $pi"
puts "area: $area"

Octal Numbers

Numbers with a leading zero, like 0644, are interpreted as octal. This is typically encountered when setting permission modes during the opening a file for writing. The leading zero may cause problems with the Tcl interpreter, when doing comparisons or assigments on numbers representing time of day. A digit that is greater than or equal to 8 preceeded by a leading zero digit will cause an illegal octal number error.


Simple Variables

Variables are initialized with the set command. Variable are typeless strings but it is important how they are initialized. Initialization with an integer (no decimal) or a real value (decimal) will produce different results. Variables with leading zeros are assumed to be in an octal format. Variables are set without a dollar sign preceding the variable name. Variables are referenced with a dollar sign preceding the variable name. This is in contrast to other scripting languages like Perl that uses dollar signs for both initialization and referencing.

#!/usr/bin/tclsh
set four 4
set four_real 4.0
set three 3
set threefourths [expr $three / $four]
puts "threefourths: $threefourths"
set threefourths_real [expr $three / $four_real]
puts "threefourths_real: $threefourths_real"

Global variables are declared in procedures, not up front. Non-global variables within a procedure are local to the procedure. The info command can be used to determine if a variable exists or not.


Strings

There is a rich set of string processing commands in Tcl. The table below is not an exhaustive list but it does contain the most commonly used string commands.

Tcl/Tk String Command Summary

Command Description
string bytelength str returns number of bytes used in for string storage
string compare str1 str2 compares string and returns -1, 0 or 1
string equal str1 str2 test equality of string and returns 1 if equal
string first str1 str2 returns the index of the first occurrence of str2 in str1, else returns -1
string last str1 str2 returns the index of the last occurrence of str2 in str1, else returns -1
string length str returns the length of str
string match pattern str returns 1 if str matches pattern
string range str start end returns substring of str from start to end
string repeat str n returns a str repeated n times
string tolower str returns a lowercased str
string totitle str returns str with the first letter capitalized
string toupper str returns a uppercased str
string trim str trims whitespace from str
string trimleft str trims whitespace from the end of str
string trimright str trims whitespace from the beginning of str

Many of these string commands have additional options such as nocase, positions, or non-default characters. See the respective manpages a more detailed description.

An example using the string command syntax follows:

#!/usr/bin/tclsh
set str1 "th"
set str2 "Is this supposed to be a good thing, Miri?"
puts "length: [string bytelength $str2]"
puts "first: [string first $str1 $str2]"
puts "last: [string last $str1 $str2]"
puts "toupper: [string toupper $str2]"

Lists

Lists are a sequence of values separated by whitespace. Braces are typically used to group items together into a single value in a list. Lists are not used to build complex data structures. Tcl lists are strings with a corresponding set of data manipulation commands. A incomplete summary of these commands are listed below.

Tcl/Tk List Command Summary

Command Description
list arg1 arg2 ... constructs a list out of several arguments
lindex list n returns the indexed element from the list
llength list returns the number of elements in a list
lrange list n m returns the range of elements of a list
lappend list arg1 arg2 ... appends elements to a list
linsert list index arg1 arg2 ... iserts elements to a list and returns a new list
lreplace list n m arg1 arg2 ... replaces elements n thru m with args and returns a new list
lsearch list value returns index of value in list, else -1
lsort list returns a sorted list

Many of these list commands also have additional options. An example using the list command syntax follows:

#!/usr/bin/tclsh
set the_list { {Red Hat} SuSE Mandrake Debian }
puts "value 0: [lindex $the_list 0]"
puts "value 1: [lindex $the_list 1]"
puts "value 2: [lindex $the_list 2]"
puts "value 3: [lindex $the_list 3]"
set the_sorted_list [lsort $the_list]
puts "value 0: [lindex $the_sorted_list 0]"
puts "value 1: [lindex $the_sorted_list 1]"
puts "value 2: [lindex $the_sorted_list 2]"
puts "value 3: [lindex $the_sorted_list 3]"

Arrays

Arrays in Tcl are associative, meaning that they are stored using a hash table. The array index to the associative array is placed within parenthesis. If the index is numeric the array syntax appears similar to other languages that do not use associative arrays. However, the indexes need not be numeric.

#!/usr/bin/tclsh
proc P_add_contact { key last_name email phone } {
    global contact_last_name
    global contact_email
    global contact_phone
    set contact_last_name($key) $last_name
    set contact_email($key) $email
    set contact_phone($key) $phone
    puts "key: $key"
    puts "name: $contact_last_name($key)"
    puts "email: $contact_email($key)"
    puts "phone: $contact_phone($key)"
    return
    }
P_add_contact 1000 aperson aperson@example.net 555-555-5555
P_add_contact 1001 bperson bperson@example.net 555-555-5556
P_add_contact 1002 cperson cperson@example.net 555-555-5557

Flow Control - if statement

Tcl is quite picky about the format of the if conditional statement. This is related to how the parser works. An example has been included to better illustrate the formatting of this conditional statement.

#!/usr/bin/tclsh
set a 1
# the if statement commented out causes a curly bracket mismatch
# if {$a == 1} {
if {$a == 0} {
    puts "a is zero"
} else {
    puts "a is not zero"
}
# need space between curly brackets
if {$a == 0}{
    puts "a is zero"
} else {
    puts "a is not zero"
}
# else is misplaced
if {$a == 0} {
    puts "a is zero"
    }
else {
    puts "a is not zero"
}
# formatted properly
if {$a == 0} {
    puts "a is zero"
} else {
    puts "a is not zero"
}
# this is also formatted properly
if {$a == 0} {
    puts "a is zero"
  } else {
    puts "a is not zero"
  }

Flow Control - loops

The syntax for loop control is covered in the next three examples.

for loop:

#!/usr/bin/tclsh
for { set loopcnt 0 } { $loopcnt < 10 } { incr loopcnt } {
    puts "loopcnt: $loopcnt"
    }

foreach loop:

#!/usr/bin/tclsh
set member_list {
    george 41
    alice 37
    fred 30
    sally 34
    dustin 23
    }
foreach {name age} $member_list {
    puts [format "name: %-20s age: %3d" $name $age]
    }

while loop:

#!/usr/bin/tclsh
set random_int 0
while { 1 } {
    # loop exit condition
    if { $random_int == 1 } {
       break
       }
    # loop processing
    set random_float [expr (10 * rand())]
    set random_int [expr (int($random_float))]
    puts $random_int
    }

Procedures - proc

Procedures must be declared before they are referenced. In a script containing many procedures main program execution may be located at the bottom of the file.

Procedures may contain optional pass variables and may also specify defaults for these variables.

Procedure names may overwrite built in commands. By defining an exit procedure the normal built in exit command will be modified. This is not recommended practice and some developers use naming conventions to avoid problems.

#!/usr/bin/tclsh
proc P_procedure1 { } {
    global variable1
    global variable2
    puts "variable1: $variable1"
    puts "variable2: $variable2"
    set variable3 [expr ($variable1 + $variable2) ]
    return $variable3
    }
proc P_procedure2 { variable3 } {
    global variable1
    global variable2
    puts "variable3: $variable3"
    return
    }
set variable1 1.0
set variable2 2.0
set temp [P_procedure1]
P_procedure2 $temp

Executing external Tcl code - source

Scripts can be subdivided into seperate sections by use of the source statement. This provides similar functionality to the "require" in Perl or "include" in the C language.

Sourcing other Tcl scripts from a main Tcl script provides a way to separate shared procedures, configuration data, environment data, and system dependent data.

#!/usr/bin/tclsh
source ex_source_err.tcl
P_msg_info "We can Tcl code common to several modules"
P_msg_warn "This is a warning message"
P_msg_err "This is an error message"

Below is a listing of the Tcl code that was contained in a different file and sourced.

#!/usr/bin/tclsh
proc P_msg_info { msg } {
    puts "INFO: $msg"
    }
proc P_msg_warn { msg } {
    puts "WARN: $msg"
    }
proc P_msg_err { msg } {
    puts "ERR: $msg"
    }

Executing system commands - exec and catch

System calls are performed by the exec command. The following example shows the exec command used with the catch command. This is useful for running a system command and capturing the output from that command. These procedures determine the operating system and hostname of the machine running the script. The return values of these procedures can be used to make system and hostname dependent decisions allowing the same code to run on different platforms and hosts.

#!/usr/bin/tclsh
set system_cmd "ls"
set system_arg "-la"
catch { exec $system_cmd $system_arg } ls_data
puts $ls_data

Command Line Arguments - argc and argv

As with many other languages Tcl can be passed arguments from the command line at the start of command execution.

#!/usr/bin/tclsh
proc P_ex_arg { v0 v1 v2 } {
    puts "v0: $v0"
    puts "v1: $v1"
    puts "v2: $v2"
    return
    }
# check for the proper number of command line arguments
if { $argc == 3 } {
    # print out the script name
    puts "executing $argv0..."
    # setup the command line arguments
    set arg1 [lindex $argv 0]
    set arg2 [lindex $argv 1]
    set arg3 [lindex $argv 2]
    # call the main routine
    P_ex_arg $arg1 $arg2 $arg3
    exit 0
} else {
    # put out an error message
    puts "usage is: ex_arg.tcl arg1 arg2 arg3"
    # exit with error
    exit 1
    }

Determining the Operating System

#!/usr/bin/tclsh
# determines operating system
proc P_determine_os { } {
    # set the subroutine name
    set sub_name {P_determine_os}
    # give the user some information
    puts "($sub_name) INFO: determining operating system"
    # execute the system command and catch the output
    catch { exec uname -sr } uname_return_data
    # tell the user what uname returned
    puts "($sub_name) INFO: uname -sr returned: $uname_return_data"
    # format the output of uname
    if { [string first "Linux" $uname_return_data] == 0 } {
        set os_type linux
    } elseif { [string first "CYGWIN_NT" $uname_return_data] == 0 } {
        set os_type cygwin
    } elseif { [string first "SunOS" $uname_return_data] == 0 } {
        set os_type solaris
    } else {
        set os_type undefined
    }
    puts "($sub_name) INFO: os_type set to: $os_type"
    return $os_type
    }
# determine operating system using a system call
P_determine_os
exit

Determining the hostname

#!/usr/bin/tclsh
proc P_determine_hostname { } {
    # set the subroutine name
    set sub_name {P_determine_hostname}
    # give the user some information
    puts "($sub_name) INFO: determining hostname"
    # do the system call
    catch { exec hostname } hostname_return_data
    # tell the user what uname returned
    puts "($sub_name) INFO: hostname returned: $hostname_return_data"
    # no translation
    set hostname $hostname_return_data
    # trim the hostname
    set hostname [string trim $hostname]
    # lowercase the hostname
    set hostname [string tolower $hostname]
    puts "($sub_name) INFO: hostname set to: $hostname"
    return $hostname
    }
# call the procedure
P_determine_hostname
exit

Determining the system time

#!/usr/bin/tclsh
# sets the current_date and current_time global variables
proc P_set_time { } {
    global current_date
    global current_time
    # set the subroutine name
    set sub_name {P_set_time}
    # format time as YYYYMMDD
    set current_date [clock format [clock seconds] -format "%Y%m%d"]
    # format the time as HHMM
    set current_time [clock format [clock seconds] -format "%H%M"]
    # give the user some information
    puts "($sub_name) INFO: current date: $current_date"
    puts "($sub_name) INFO: current time: $current_time"
    return
    }
# call the procedure
P_set_time
exit

File managenemt - file join

One of the benefits of Tcl and Tk is its ability to execute cross platform. File pathnames (slash, backslash, colon) and file formats (cr-lf combinations) have always been problematic to programmers. Tcl solves this problem by building up pathnames using the file join command.

#!/usr/bin/tclsh
# produces a text file
proc P_create_file { } {
    # set the subroutine name
    set sub_name "P_create_file"
    # build up the file name
    set abs_file_name [file join "/home" "gwhitema"]
    set abs_file_name [file join $abs_file_name "tcl"]
    set abs_file_name [file join $abs_file_name "training"]
    set abs_file_name [file join $abs_file_name "ex_file_join.txt"]
    # tell the user what is happening
    puts "($sub_name) INFO: creating file: $abs_file_name"
    # open the html file
    set file_id [open $abs_file_name w 0644]
    # write some text to the file
    puts $file_id "this is some text"
    # close the file
    close $file_id
    return
    }
# call the procedure
P_create_file
exit

Reading from a file

Reading data from a file line by line is a common task in programming. The following example details how to open a file for reading and split the data in the file on the new line.

#!/usr/bin/tclsh
proc P_read_file { file_name } {
    # open the file
    set file_id [open $file_name r]
    # read in the file line by line
    foreach line [split [read $file_id] \n] {
        # process the line
        puts $line
        }
    # close the file
    close $file_id
    return
    }
# call the procedure
P_read_file "ex_file_read.txt"
exit

Writing to a file

Writing data to a file is also a common programming task. The following examples details how to open a file for writing. Notice the leading zero in the octal file permission data field when the file is initially opened.

#!/usr/bin/tclsh
set file_name "ex_file_write.txt"
# open the dst file for write
set file_id [ open $file_name w 0644 ]
# put some data in the file
for { set loopcnt 0 } { $loopcnt < 10 } { incr loopcnt } {
    puts $file_id "loopcnt: $loopcnt"
    }
# close the file
close $file_id

fconfigure

Tcl can also produce file formats targetted for one OS while executing on a different OS. This is accomplished by usign the fconfigure command.

#!/usr/bin/tclsh
# produces a text file
proc P_create_file_fconfigure { } {
    # set the subroutine name
    set sub_name "P_create_file_fconfigure"
    # build up the file name
    set abs_file_name [file join "/home" "gwhitema"]
    set abs_file_name [file join $abs_file_name "tcl"]
    set abs_file_name [file join $abs_file_name "training"]
    set abs_file_name [file join $abs_file_name "ex_fconfigure.txt"]
    # tell the user what is happening
    puts "($sub_name) INFO: creating file: $abs_file_name"
    # open the file
    set file_id [open $abs_file_name w 0644]
    # generate using unix line terminations
    # fconfigure $file_id -translation lf
    # generate using dos line terminations
    fconfigure $file_id -translation crlf
    # generate using mac line terminations
    # fconfigure $file_id -translation cr
    # write some text to the file
    puts $file_id "this is line 1"
    puts $file_id "this is line 2"
    puts $file_id "this is line 3"
    # close the file
    close $file_id
    return
    }
# call the procedure
P_create_file_fconfigure
exit

Regular Expressions - regexp

Regular expressions are supported through the use of the regexp statement. The following example reads in a file and strips comments indicated by a # sign in the first column.

#!/usr/bin/tclsh
# setup the filename
set file_name ex_regexp_in.txt
# open the file for reading
set file_id [open $file_name r]
# read in the file line by line
foreach line [split [read $file_id] \n] {
    # process the line
    if { [regexp "(ˆ#)" $line match] == 0 } {
        puts $line
        }
    }
# close the file
close $file_id
This is the file used as input to the regexp example above.
# this is comment 1
cmd1
# this is comment 2
cmd2 arg1 arg2
# this is comment 3
cmd3 arg1 arg2 arg3
# this is comment 4
cmd4
# this is comment 5
cmd5

regsub

String subsititutions are supported through the use of the regsub statement.

#!/usr/bin/tclsh
# set up the src filename
set src_file_name "input.txt"
# set up the dst filename
set dst_file_name "output.txt"
# open the src file for read
set src_file_id [ open $src_file_name ]
# open the dst file for write
set dst_file_id [ open $dst_file_name w ]
# read the src line by line
while {[gets $src_file_id line] >= 0} {
    # put your from-to translation strings here
    puts $dst_file_id [regsub -all {cool} $line {dorky} line]
}
# close both files
close $src_file_id
close $dst_file_id

Tk Geometry Management

Tk controls the construction of widgets using one or more geometry managers. Geometry managers control the resizing and location of widgets during script execution. Various combinations of geometry managers can be used within a single Tcl/Tk script.


Tk Widgets

The following table lists the basic types of widgets used by Tk. This is not a complete table nor does it contain the file dialog widgets available for use.

Basic Tk Widget SummaryWidget Description
button creates a button to execute a command
radiobutton creates a set of buttons, 1 of n can be selected
checkbutton creates a set of buttons, any number can be selected
entry used for a single text input line
message creates a message text window
label used for labelling other widgets with read only text
scale slider control that calls a routine when the slider position changes
menubutton displays a scrolldown menu
menu holds menu pulldown items
listbox creates a list box that can be scrolled
scrollbar creates a scrollbar that is used to control other widgets
frame creates a frame to control the grouping of other widgets
toplevel creates a top level window with controls from the window manager
text creates a text window that can be edited
canvas creates a graphic window that is used for drawing and image display

button

#!/usr/bin/wish
# button command processor
proc P_process_button { button_cmd_string } {
    puts $button_cmd_string
    return
    }
# set the font size (pts)
set font_size 24
# frames for columns
frame .c0
frame .c1
frame .c2
# button for upper case characters
button .c0.b0 -text "B0" \
-font "-family arial -weight bold -size $font_size" \
-background #8080e0 -command { P_process_button "button 0" }
button .c0.b1 -text "B1" \
-font "-family arial -weight bold -size $font_size" \
-background #8080e0 -command { P_process_button "button 1" }
button .c1.b0 -text "B2" \
-font "-family arial -weight bold -size $font_size" \
-background #8080e0 -command { P_process_button "button 2" }
button .c1.b1 -text "B3" \
-font "-family arial -weight bold -size $font_size" \
-background #8080e0 -command { P_process_button "button 3" }
button .c2.b0 -text "B4" \
-font "-family arial -weight bold -size $font_size" \
-background #8080e0 -command { P_process_button "button 5" }
button .c2.b1 -text "exit" \
-font "-family arial -weight bold -size $font_size" \
-background #ff0000 -command { exit }
# pack the buttons
pack .c0.b0 -side top -fill both -expand true
pack .c0.b1 -side top -fill both -expand true
pack .c1.b0 -side top -fill both -expand true
pack .c1.b1 -side top -fill both -expand true
pack .c2.b0 -side top -fill both -expand true
pack .c2.b1 -side top -fill both -expand true
# pack the column frames
pack .c0 -side left -fill both -expand true
pack .c1 -side left -fill both -expand true
pack .c2 -side left -fill both -expand true

label

#!/usr/bin/wish
proc P_process_button { } {
    global current_string
    global display_width
    if { [string compare $current_string "OFF"] == 0 } {
        set current_string "ON"
    } else {
        set current_string "OFF"
        }
    .c0.l0 configure -text $current_string -width $display_width
return
}
# display adjustments
tk scaling 1
set font_size 24
set display_width 10
set xpadding 10
set ypadding 10
# setup the current label string
set current_string "OFF"
# frame for column 0
frame .c0
# button
button .c0.b0 -text "toggle" \
-font "-family arial -weight bold -size $font_size" \
-background #808080 -command P_process_button
# label widget
label .c0.l0 -text $current_string \
-font "-family arial -weight bold -size $font_size" \
-width $display_width
# pack the label, button, and column
pack .c0.l0 -side top -fill both \
-expand true -padx $xpadding -pady $ypadding
pack .c0.b0 -side top -fill both
pack .c0

entry

#!/usr/bin/wish
proc P_contact_entry { } {
    frame .contact_frame -borderwidth 2 -relief raised
    label .contact_frame.last_name_label -text "last name"
    entry .contact_frame.last_name_entry -textvariable last_name -width 40
    label .contact_frame.phone_label -text "phone"
    entry .contact_frame.phone_entry -textvariable phone -width 20
    label .contact_frame.email_label -text "email"
    entry .contact_frame.email_entry -textvariable email -width 40
    button .contact_frame.save_button -text "save" \
    -command { P_save_contact $last_name $phone $email }
    button .contact_frame.exit_button -text "exit" \
    -command { exit }
    pack .contact_frame.last_name_label -side top -fill x -expand true
    pack .contact_frame.last_name_entry -side top -fill x -expand true
    pack .contact_frame.phone_label -side top -fill x -expand true
    pack .contact_frame.phone_entry -side top -fill x -expand true
    pack .contact_frame.email_label -side top -fill x -expand true
    pack .contact_frame.email_entry -side top -fill x -expand true
    pack .contact_frame.save_button
    pack .contact_frame.exit_button
    pack .contact_frame -fill both -expand true
    return
    }

proc P_save_contact { last_name phone email } {
    puts ""
    puts " $last_name"
    puts " $phone"
    puts " $email"
    puts ""
    return;
    }
P_contact_entry

text

#!/usr/bin/wish
# title on main window
wm title . "Text Widget Example"
# text widget with y scroll bar
text .txtwin -width 80 -height 20 -bg grey \
-yscrollcommand ".yscroll set"
# scrollbar widget
scrollbar .yscroll -command ".txtwin yview"
# pack the text window
pack .txtwin -side left -fill y
# pack the scrollbar
pack .yscroll -side right -fill y

menu

#!/usr/bin/wish
proc P_menu { } {
    global editor
    frame .mbar -borderwidth 2 -relief raised
    frame .msg -borderwidth 2 -relief raised
    menubutton .mbar.file -text "file" -menu .mbar.file.menupull
    menu .mbar.file.menupull
    .mbar.file.menupull add command \
    -label "Edit" -command { exec $editor }
    .mbar.file.menupull add command \
    -label "Exit" -command { exit }
    text .msg.txtwin -width 80 -height 20 -bg grey \
    -yscrollcommand ".msg.yscroll set"
    # scrollbar widget
    scrollbar .msg.yscroll -command ".msg.txtwin yview"
    pack .mbar.file -side left
    pack .msg.txtwin -side left -expand true -fill both
    pack .msg.yscroll -side left -fill y
    pack .mbar -side top -fill x
    pack .msg -side top -fill both -expand true
    return
    }
set editor "gvim"
P_menu

References

  1. Welch, Brent B., Practical Programming in Tcl and Tk, Third Edition, ISBN 0-13-022028-0, Prentice Hall, Upper Saddle River, NJ, 2000
  2. Nelson, Christopher, Tcl/Tk Programmers Reference, ISBN 0-07-212004-5, Osborne McGraw-Hill, 2600 Tenth Street, Berkeley, CA, 94710, 2000
  3. Flynt, Clif, Tcl/Tk for Real Programmers, ISBN 0-12-261205-1, Academic Press, 1999
  4. Young, David H., The Visual Tcl Handbook, ISBN 013461674X, Prentice Hall, 1996
  5. Ousterhout, Dr. John K., Tcl and the Tk Toolkit, 0-201-63337-X, Addison-Wesley Publishing, 1994
  6. Ousterhout, Dr. John K., The History of Tcl, http://tcl.activestate.com/advocacy/tclHistory.html
  7. USENET, comp.lang.tcl
  8. Tcl Consortium, http://www.tclconsortium.org/resources/
  9. Scriptics, http://www.scriptics.com/
  10. ActiveState, http://www.activestate.com/
  11. ActiveState Tcl, http://tcl.activestate.com/
  12. Tcl for EDA, http://www.tclforeda.net/