Programming 版 (精华区)
发信人: Gaffe (时飞), 信区: Programming
标 题: tcl&tk
发信站: 哈工大紫丁香 (2002年01月02日12:05:26 星期三), 站内信件
◇ tcl & tk
----------------------------------------------------------------------------
----
From: syc@cc.ntu.edu.tw (Shiau Yong-Ching)
Newsgroups: csie.bbs.xwindow,csie.bbs.linux,tw.comp.unix
Subject: TCL & TK
Date: 3 Mar 1994 11:27:02 GMT
Organization: National Taiwan University
大家好,
一提到直译语言,令人印象最深刻的,想必是BASIC了。没错,
BASIC 陪伴很多人进入PC的奇妙世界,甚至到今天,Visual
Basic 在Windows 下依然魅力十足,把Interpretor 的优点发挥
的淋淋尽致—程式发展快、方便易学。在UNIX的世界里,C几乎
是程式语言的代名词,BASIC 早已被人们所淡忘。但是,UNIX下
是否有像BASIC 一般简单易学,功能强大的解译语言呢?答案是
肯定的,而且功能皆有过之而无不及,举凡lisp、prolog等人工
智慧语言,或者像Perl、tcl/tk 皆是,而且都有提供方便的图
型界面,使得在X window下设计程式方便不少。以下文章就是在
下寒假研究tcl/tk的心得,提供大家参考;并且强力推销tcl。
******
一、什麽是tcl?什麽是tk?
tcl 是Tool Command Language 的缩写,而tk是一个X window的
Tool Kits,是tcl在X Window System 的应用。tcl 是一种解译
语言,也是一套C的函式库。为什麽这样说呢?因为tcl 的解译
器被设计成一个C的函式库,提供基本的命令与控制结构,并且
使用tcl 的任何程式皆可以根据tcl 的规格撰写C程式与之链结
增加新的命令,以提高关键程式的效率、或增加新的特色。如tk
就是这样子的示□。废话少说,以下先来个示□:
┌———————————————————————————————┐
│ tk的解译器叫wish,是WIndowing SHell 的简称。只要在提示号 │
│ 下(xterm 下)输入wish就可以了。接下来你可以看到一个空白 │
│ 的视窗出现,xterm 下的提示号也变成了wish的提示号。此时, │
│ 在提示号输入以下两行指令,就可以见到最简单,最让人惊奇的 │
│ tk程式了: │
│ button .b1 -text "Hello,World!" -command exit │
│ pack .b1 │
│ 下完第二个指令後,原本空白的视窗就变成一个印有Hello,World │
│ 的立体按钮,而且滑鼠移近时会变成高亮度。但是别急,且慢按键 │
│ 在输入两个命令看看: │
│ │
│ button .b2 -text "Hello,TCL/TK" -command "destroy .b2" │
│ pack .b2 │
│ │
│ 此时,萤幕上会出现第二个按钮。以下两个命令可以更改颜色: │
│ .b1 configure -background red │
│ .b2 configure -foreground green │
│ 按下第二个按钮会使第二个按钮消失,而第一个按钮会结束程式。 │
│ │
│ 每次这样写很麻烦,但是你也可以照UNIX的规矩把程式写成一个档 │
│ 案hello,再执行之。( 当然要先chmod +x hello) │
│ hello的内容:(第一行的内容可由`which wish`指令得知) │
│ #!/usr/local/bin/wish -f │
│ button .b -text "Hello,World!" -command exit │
│ pack .b │
└———————————————————————————————┘
*注1:请查询系统管理者详细的路径。
注2:tcl/tk原始码可以在NCTUCCCA:/X/contrib/下找到。
注3:cc.ntu.edu.tw的使用者其wish的路径为/remote/bin/wish
注4:交谈式的wish的命令行编辑非常原始,使用者可以用fep 或ile
两个front end 程式达到类似tcsh/bash/ksh 的行编辑。
注5:Linux/386BSD的使用者(应该说XFree86的使用者)应该安装时就有
tcl/tk了。
二、关於tcl
因为tk是基於tcl 语言而来的,因此我们有必要先了解tcl 。
与tk相同,tcl 也附了一个交谈式解译器tclsh ,可供线上学习tcl之用。
tcl 的语法非常简单,基本上就是与Shell的语法类似。学过一点点shell
programing的人非常容易进入状况:
A.一个tcl 程式是由好几个tcl 叙述组成的。
B.一个tcl 叙述与平常在shell 下面的命令一模一样,如前面
hello,world 的例子一样,第一个字是命令,剩下的全部是
该命令的参数。
C.tcl 除了命令外就只有变数。变数与shell 变数一样,只有
一种型别:字串。钱号可以取出变数的值。
D.tcl 对每一个叙述最多只做一次变数代换。而被大括号括住
的部份不做任何处理。
E.tcl 会优先执行被方括号括住的叙述,并将其结果当成原来
命令的一部份。这与shell 的重音符号相同(mkdir `echo Hello`
)
以下就是一些□例:
unix% tclsh
tcl% set x 100 输出 100
tcl% set y 200 200
tcl% expr $x + $y 300
tcl% set z [expr x+y] 300, z = 300
tcl% set a [set b 100] a = b = 100
tcl% expr (3>4)||(6<=7) 1
tcl% expr 14.1*sin($x)
tcl% set organization "Taiwan University" (两句同意,只是
□
tcl% set organization {Taiwan University} (引号会做变数代换
□
[以下省略tcl的提示号]
tcl的procedure:
proc power {base p} {
set result 1
while {$p > 0} {
set result [expr $result*$base]
set p [expr $p-1]
}
return $result
}
power 2 6 可得 64
power 1.15 5 2.01136
仔细观察procedure的demo,其实tcl 并没有procedure结构的语法。
proc只是一个命令,接受4个引数:
proc 新命令名字 参数 一段tcl程式码
其中,参数与tcl程式码用大括号括起来的原因是我们不希望tcl 现在
就执行这些程式码,而是当procedure被呼叫时才执行。while结构也是
如此:
while 判断 程式码
因为我们希望每次while执行时$result,$p的值都会变。如果不用大括号
括起来,则所有的值在tcl解译的时候就固定了,while回圈永远也不会
结束。
与大括号相反,eval命令可以把一个字串当成tcl 命令执行:
eval {set x 123} 等於 set x 123
eval "set x 123" 同上
eval可以造成tcl 对同一叙述parse两次,解决一些难缠的问题:
exec rm [glob *.o]
会告诉你:
"a.o b.o c.o" not found
正确的解法是叫tcl 再parse一遍命令行:
eval "exec rm [glob *.o]"
tcl 的array:不须宣告,直接用即可,但是只有一维阵列而已。
set days_of_a_month(Jan) 31
set days_of_a_month(Fab) 28
多维阵列可用单维阵列模拟:
set matrix(1,1) 100
set matrix(3,9) 50
set matrix($x,$y) 66
set z $matrix(6,6) 77
阵列的index其实为 "1,1" 、 "3,9" 与 "$x,$y"
相关的命令:
set var value
append var value [value2 vaule3 ...]
incr var [increament] /* default = 1 */
unset var [var2 var3 ...]
tcl 还有一种之料结构叫list
set x {Sun Mon Tue Wed Thu Fri Sat}
lindex $x 1 输出 Mon
lindex {a b {c d e} f g} 2 输出 "c d e"
concat {a b} {c d} e 输出 "a b c d e"
list {a b} {c d} e "{a b} {c d} e"
llength { {a b} e f} 3
llength {} 0
llength a 1
linsert $x 2 a b c Sun Mon a b c Tue ...
linsert $x 0 a a Sun Mon ...
lreplace $x 0 a a Mon Tue ...
lrange $x 0 1 Sun Mon
lappend $x a b c
lsearch $x Sat
lsearch -glob $x S* /* Wild Cards */
lsearch -regexp /* regular expression */
lsort [-decreasing|-integer] $x
Strings & Lists
set x a/b/c
set y /usr/local/bin/wish
split $x / 输出 a b c
split y {} usr local bin wish
反函数为join
Lists & Commands:
其实tcl 语言本身就是一个list,瞧,最後一个是command或是
list:
button .b -text "Reset" -command {set x 0}
list可以解决一些难以构成的命令:
假设有一个情况,我们写了下列命令:
button .b -text "Reset" -command "set x $InitValue"
此命令的情况是我们希望Reset button按下後把 x设回
InitValue,可是天不从人愿,如果$InitValue是"tcl tk"
则Command变成set x tcl tk,引述个数不对了。
如果改成:
button .b -text "Reset" -command {set x $InitValue}
则x 值取决於按钮时的InitValue,而非真正的InitValue
所以可用下列方法解决:
button .b -text "Reset" -command [list set x $initValue
]
控制结构:
if 判断 [then] 叙述 elseif 叙述 elseif 叙述 [else] 叙述
then 与else 皆可省略。
while : (make b the reverse of a)
set b ""
set i [expr [llength $a] -1]
while {$i >= 0} {
lappend b [lindex $a $i]
incr i -1
}
for:
set b ""
for {set i [expr [llength $a] -1]} {$i >=0} {incr i -1
} .
lappend b [lindex $a $i]
}
foreach:
set b ""
foreach i $a {
set b [linset $b 0 $i]
}
注意,受限於tcl 语法,大括号不能独立一行:
while {}
{
}
break与continue也都有效。
switch命令:
switch $x {
Mon {incr days(Mon)}
Tue {incr days(Tue)}
default {...}
}
亦可写成:
switch $x Mon {...} Tue {...} default {...}
或
switch $x \
Mon {...} \
Tue {...} \
default {...}
如果动作相同可用 - 代表。
switch $x {
1 -
3 -
5 -
7 -
9 {incr odd}
default {incr even}
}
副程式:
同csh,tcl也有source 命令:
source tclInit.tcl
procedure:
proc name ArgList Body
定义一个叫做name 的procedure,
如果ArgList的最後一个为args,则此procedure
为不定引数函数,而args为一list。
global name1 name2 ...
使用global中的name1 name2变数,而非自定local变数
return value
uplevel [level] script1 script2...
类似inline函式,把stript1 script2 ...串起来
然後在上一层中执行,而非在procedure自己的stack
内执行(可以更改上一层的变数)。
upvar [level] name localname [name1 localname1] ...
引用上一层的变数name,但是在本procedure内用
localname存取之。(call by reference)
uplevel例:
proc do {varName first last body} {
upvar $varName v
for {set v $first} {$v <= $last} {incr v}
uplevel $body
}
}
set a {}
do i 1 5 {
lappend a [expr $i*$i]
}
set a 显示 1 4 9 16 25
如果不用uplevel,则$body就不可能存取到 a变数了。
Errors& exceptions:
catch {
tcl 程式码
} messages
如果程式码有错,catch return 1,否则为0,messages为实际的错误讯息。
以下没力气打中文,写不下去了,抄两个玩具给大家欣赏 :-b
#!/usr/local/bin/wish -f
proc power {base p} {
set result 1
while {$p > 0} {
set result [expr $result*$base]
incr p -1
}
return $result
}
entry .base -width 6 -relief suken -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]}
# End of File
注: -relief sunken的意思是凹陷的轮廓。
本程式产生一个视窗:
┌——————————————————————————┐
│〔 A 〕to the power 〔 B 〕 is 〔 〕│
└——————————————————————————┘
只要输入A,B就可以得到A的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> { <- 当.entry 收到<Return>这个event时
set id [incr id]
if {$id > 5} {
destroy .b[expr $id -5] <- tcl的变数名也可以用凑的
└> 删除第5次前的命令
}
button .b$id -command "exec <@stdin >@stdout $cmd" -text $cmd
pack .b$id -fill x <- 显示按钮,且水平(x)方向填满。
.b$id invoke <- 模拟按钮被按下
.entry delete 0 end <- 清除输入行
}
#end of file
本程式产生一个输入行,可以下命令,并且把过去的5个命令记录下来,
用按钮就可以执行。
***
看到这里,您是否同意tcl/tk是UNIX世界的BASIC呢?
本篇文章是我阅读一本书:tcl and tk toolkit的部份心得。这本书已於1994年由
Addison-Wesley Publishing Company,Inc.出版(ISBN 0-201-63337-X)。此书
网路上有postscript档案,但是我不认为大家有□情逸致印个500页左右的
书吧---用10ppm的雷射印表机也要50几分钟、实际上用Postscript输出更慢,
还会卡纸哩:)最好是找找看有没有进口。
tcl/tk在USENET上有自己的讨论群:comp.lang.tcl各位可以参考其FAQ。FAQ可在
NCTUCCCA:/USENET/FAQ/comp/lang/tcl拿到。
UNIX下的Interpretor种类繁多,功能复杂,但愿这篇文章能收到抛砖引玉之效
使有人愿意写些中文文件来介绍与X Window 整合的其他Interpretor,如tkperl
、Prolog等。甚至是一些Windows的程式设计工具,如SUIT,xvwindow等library
使得 X Windows Programing对入门者不再是梦靥。
以上所提及的软体更是网路上可以免费取得的合法软体,特别是Linux下全部都有。
ps: 上学期末在天龙书局看到Larry Wall的Programing Perl,对perl有兴趣者可
以去买,保证不会後悔!
pps: tk目前的版本无法处理16bits的字集,即Botton..无法看到中文,可能要
等到tk 4.0。
======================================================
Shiau Yong-Ching (萧永庆)
E-mail: syc@cc.ntu.edu.tw Phone: 7358499 - 717
Department of Electrical Engineering, Taiwan University
--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: riee3.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:412.967毫秒