Scripting Language - TCL/TK: 5.1 How Not To Use Scripting Languages
Scripting Language - TCL/TK: 5.1 How Not To Use Scripting Languages
cripting is difficult to define. It has existed for a long time - the first scripting languages were
job control languages such as the shell program found in Unix systems. Modern scripting
languages such as Perl, Tcl, Python, awk, Ruby and so on are general purpose, but often they
have more powerful basic operations than those found in conventional general purpose computer
languages. For example it is common to have operators that perform regular-expression pattern
matching in a scripting language.
Scripting languages are normally interpreted, and the interpreter contains the routines to do the
pattern matching. One line of script code may be equivalent to 100 lines of C. However, the
overhead in having a (say) 3MB script interpreter is sometimes a problem, although less so these
days.
Perl is widely used, as it is found in active web page developments. Tcl/Tk is useful for GUI
development, allowing us to prototype new GUI applications quickly.
Scripting languages are very good at some things, but sometimes frustratingly bad at other things.
For example, many scripting languages use associative, text-based array indexes, and so a simple
array lookup may take 1000 times longer than an equivalent lookup in a compiled language.
For this reason, it is common to mix scripting and other languages.
45
46
5.2 Tcl/Tk
Wish - the windowing shell, is a simple scripting interface to the Tcl/Tk language. The language
Tcl (Tool Command Language) is an interpreted scripting language, with useful inter-application
communication methods, and is pronounced tickle. Tk originally was an X-window toolkit
implemented as extensions to tcl. However, now it is available native on all platforms.
The program xspin is an example of a portable program in which the entire user interface is
written in wish. The program also runs on PCs using NT or Win95, and as well on Macintoshes.
CODE LISTING
HelloWorld.tcl
#!/usr/local/bin/wish8.1 f
button .quit text "Hello World!" command {exit}
pack .quit
5.2 Tcl/Tk
47
If you create this as a file, and make it executable, you should be able to run this simple graphical
program.
Tcl commands are separated by a new line, or a semicolon, and arrays are indexed by text:
set a(a\ text\ index) 4
48
a will be "12b"
b will be "1212b"
Command substitution: The []s are replaced by the value returned by executing the Tcl command doit.
set a [doit param1 param2]
Backslash substitution:
set a a\ string\ with\ spaces\ \
and\ a\ new\ line
File Access
Miscellaneous
open <name>
source <NameOfFile>
read <fileID>
global <varname>
close <fileID>
catch <command>
cd <directoryname>
List operators:
split
<string> ?splitcharacters?
concat <list> <list>
lindex <list> <index>
... + lots more
Control structures:
if {test} {thenpart} {elsepart}1 while {test} {body}
for {init} {test} {incr} {body}
continue
case $x in a {a-part} b {b-part}
1
The Tcl/Tk words then and else are noise words, which may be used to increase readability.
5.2 Tcl/Tk
49
label <name>
canvas <name>
button <name>
frame <name>
... and so on
optional
optional
optional
optional
parameter
parameter
parameter
parameter
pairs
pairs
pairs
pairs
...
...
...
...
When you create a widget ".b", a new command ".b" is created, which you can use to further
communicate with it. The geometry managers in Tk assemble the widgets:
% pack <name> .... where ....
CODE LISTING
SimpleProg.tcl
#!/usr/local/bin/wish8.1 f
text .log width 60 height 5 bd 2 relief raised
pack .log
button .buttonquit text "Quit" command exit
pack .buttonquit
button .buttondate text "date" command getdate
pack .buttondate
proc getdate {} {
set result [exec date]
.log insert end $result
.log insert end \n
}
50
The mainline of the source just creates the buttons, and packs the frame:
CODE LISTING
tkpaint1.tcl
#! /usr/local/bin/wish f
set thistool rectangle
set thisop grow
set thiscolour black
button .exitbtn
bitmap @exit.xbm
command exit
button .squarebtn bitmap @square.xbm
command setsquaretool
button .circlebtn bitmap @circle.xbm
command setcircletool
button .shrnkbtn bitmap @shrink.xbm
command "set thisop shrnk"
button .growbtn
bitmap @grow.xbm
command "set thisop grow"
button .printbtn bitmap @print.xbm
command printit
button .colorbtn bitmap @newcolour.xbm command setanewcolour
canvas .net width 400 height 400 background white relief sunken
canvas .status width 40 height 40 background white relief sunken
pack
pack
pack
pack
pack
tkpaint4.tcl
proc beginmove {x y} {
global oldx oldy
set oldx $x; set oldy $y
}
proc domove {item x y} {
global oldx oldy
.net move $item [expr "$x $oldx"] [expr "$y $oldy"]
set oldx $x; set oldy $y
}
proc altersize {item x y z} {
.net scale $item $x $y $z $z
}
proc printit {} {
.net postscript file "pic.ps"
}
5.2 Tcl/Tk
51
tkpaint2.tcl
proc makenode {x y} {
global nodes oldx oldy thistool thiscolor
set nodes [expr "$nodes+1"]
set x1 [expr "$x20"]; set y1 [expr "$y20"]
set x2 [expr "$x+20"]; set y2 [expr "$y+20"]
if {[string compare $thistool "oval"] == 0} {
.net create oval $x1 $y1 $x2 $y2 tag node$nodes fill $thiscolor
}
if {[string compare $thistool "rectangle"] == 0} {
.net create rectangle $x1 $y1 $x2 $y2 tag node$nodes fill $thiscolor
}
.net bind node$nodes <Enter> ".net itemconfigure node$nodes width 5"
.net bind node$nodes <Leave> ".net itemconfigure node$nodes width 1"
.net bind node$nodes <ButtonPress3> "beginmove %x %y"
.net bind node$nodes <B3Motion> "domove node$nodes %x %y"
.net bind node$nodes <ButtonPress2> "dothisop node$nodes %x %y"
}
proc dothisop {item x y} {
global thisop
if {[string compare $thisop "shrink"] == 0} {
altersize $item $x $y 0.5
}
if {[string compare $thisop "grow"] == 0} {
altersize $item $x $y 2.0
}
}
More routines:
CODE LISTING
tkpaint3.tcl
proc setcircletool {} {
global thistool thiscolor
set thistool oval
.status delete statusthingy
.status create oval 10 10 37 37 tag statusthingy fill $thiscolor
}
proc setsquaretool {} {
global thistool thiscolor
set thistool rectangle
.status delete statusthingy
.status create rectangle 10 10 37 37 tag statusthingy fill $thiscolor
}
proc setanewcolor {} {
global thiscolor
if {[string compare $thiscolor "black"] == 0} {
set thiscolor green
} { if {[string compare $thiscolor "green"] == 0} {
set thiscolor blue
} { if {[string compare $thiscolor "blue"] == 0} {
set thiscolor red
} { if {[string compare $thiscolor "red"] == 0} {
set thiscolor orange
} { set thiscolor black }
}
}
}
.status itemconfigure statusthingy fill $thiscolor
}
52
5.2.3 C/Tk
In the following example, a Tcl/Tk program is integrated with a C program, giving a very small
codesize GUI application, that can be compiled on any platform - Windows, UNIX or even the
Macintosh platform without changes.
CODE LISTING
#include <stdio.h>
#include <tcl.h>
#include <tk.h>
CplusTclTk.c
The first half of the listing is a C string containing a Tcl/Tk program. The second part of the
listing is C code which uses this Tcl/Tk.
5.2 Tcl/Tk
53
And the result is a simple viewer for GIF images. The total code size is 57 lines. The application
looks like this when running:
54
55
Menus.tcl
{} 0 OK
56
set a expr 3 + 4
6. Write a minimal Tk application which puts up a single File menu with a Quit item in it.
Further study
http://www.pconline.com/~erc/tclwin.htm
http://tcl.activestate.com/scripting/
http://www.msen.com/~clif/TclTutor.html
TclTk widgets:
http://www.comp.nus.edu.sg/cs3283/ftp/CS-TR-94-5.pdf,
http://www.comp.nus.edu.sg/cs3283/ftp/demos.tar.