tcl语言概览

本章主要用一系列脚本介绍 tcl 和 tk, 其目的在于展示 tck 和 tk 的整体结构,以及它们能够做到什么。

1. 入门

tcl 命令

命令类似于 shell 中的命令,接收参数然后返回结果。每一条 tcl 命令都会返回一个结果。如果该命令没有有意义的结果,他会返回一个空字符串。

例如: expr 命令

expr 14.1 * 6 * sin(.2)
expr rand()

# 和 C 语言一样,布尔型结果用数值表达,1 表示真,0 表示假
expr (3 > 4) || (6 <= 7)
tk 界面
button .b -text "Hello" -command "puts Good-bye!; exit"
pack .b

tk 中构建图形用户界面的基本单元是组件(widget), 一个组件就是一个有特定外观和行为的窗口。

组件是分层组织的例如 .a 代表主组件的一个子组件, .a.b.c 代表 .a.b 的一个子组件。

变量与替换
set a 1.5
set b [expr $a * 4]
puts $b

变量替换: tcl 将 $ 符和它后面的变量名替换为改变量的值,因此执行 expr $a * 4 时, expr 接收的参数实际是 1.5 * 4

变量值总是可以用字符串表示,但可能是以原生二进制形式保存的

命令替换: 使用 [ ] 可以将一条命令的执行结果作为另一条命令的输入参数

控制结构

tcl 过程 (procedure)

# 计算阶乘
proc factorial {val} {
    set result 1
    while {$val > 0} {
        set result [expr $result * $val]
        # incr 命令将对整型变量 val 加上 -1
        incr val -1
    }

    return $result
}

puts [factorial 3]

tcl 中大括号和双引号所包含的内容都可以嵌入空格,但是2点不同

  1. 大括号可嵌套
  2. 大括号里的内容会原封不动传给命令,不会发生替换

proc 命令获取三个参数,过程名称,用空格分隔的参数名列表以及过程块

proc 会把过程名称作为一个新命令加入到 tcl 解释器

括号替换原则

在编写Tcl脚本时一个很困难的问题就是“替换”,在你需要它的时候保证它发生,在你不需要它的时候保证它不发生。

过程块必须用大括号括起来,是因为当过程块作为一个参数传递给proc时,我们不希望发生变量替换或命令替换,我们希望这些替换在过程块作为Tcl脚本处理的时候发生。

while命令块用大括号括起来的原因是一样的:我们不是希望替换在解析while命令的时候发生一次,而是希望每次while循环处理循环块的时候都进行替换。

while的参数{$val>0}也需要这个大括号。否则变量val的值只在解析while命令时替换一次,那样这个while就会陷入死循环。你可以试验一下把这个示例中的大括号用双引号代替,看看会出现什么情况。

例如

set a 12

set b "$a"
set c {$a}

puts $b
puts $c
局部变量

过程中的变量为局部变量,包括参数 (参数传入方式为复制其值)

2. 关于 tcl 语言

tcl 没有确定的语法来解释整个语言,其包括的只是十多条用于解析参数和执行替换的简单原则。

Tcl脚本的具体行为是由所执行的命令确定的。命令决定了应该把一个参数视为它所代表的值,还是变量名,或是要执行的代码块等。

例如

while {$val > 0} {
    set result [expr $result * $val]
    incr val -1
}

在处理这个命令时,Tcl解释器只知道这个命令有三个词,其中第一个是命令名。Tcl解释器并不知道wile的第一个输入参数是表达式,第二个是Tcl脚本。

完成对这个命令的解析之后,Tcl解释器会把这个命令中的参数单词都传给while,然后wile命令会把第一个参数作为表达式,把第二个参数作为Tcl脚本处理。

如果表达式的值非零,那么while就会把第二个参数传回Tcl解释器进行处理。到了这一步,解释器就会把这第二个参数作为脚本对待(即执行命令,进行变量替换,调用expr、set以及incr命令

现在考虑下面示例

set {$val > 0} {
    set result [expr $result * $val]
    incr val -1
}

对于Tcl解释器来说,set命令与while命令唯一的不同就是它们的命令名不同

解释器处理这个命令的方式与while命令一样,唯一的不同之处是执行命令时调用的过程不同

set命令将其第一个参数作为变量名,第二个参数作为变量的值,因此,这里它会设置一个变量,变量名为$val>0

又因为 set 把第二个参数作为变量值,并没有作为脚本传回解释器执行,因此最终该变量值会原封不动的等于括号里的内容

倘若括号里的内容是引号而不是大括号,那么tcl在处理这条命令时,会先发生替换才传给 set

这样做的一个有意义的结果是,脚本可以为命令定义全新的控制结构,这一功能是大多数语言不具备的。

3. 事件绑定

考虑下面这个示例

proc factorial {val} {
    set result 1
    while {$val > 0} {
        set result [expr $result * $val]
        incr val -1
    }

    return $result
}

entry .value -width 6 -relief sunken -textvariable value
label .description -text "factorial is"

label .result -textvariable result

button  .calculate -text "Calculate" \
    -command {set result [factorial $value]}

bind .value <Return> {
    .calculate flash
    .calculate invoke
}

grid .value .description .result -padx 1m -pady 1m
grid .calculate - - -padx 1m -pady 1m

bind 命令有三个参数: 组件名, 事件说明, 以及指定组件中指定事件发生时调用的 tcl 脚本

事件说明符表如下:

事件说明符含义
<Button-1>按下 1 号鼠标键
<1><Button-1> 的简写
<ButtonRelease-1>释放 1 号鼠标键
<Double-Button-1>双击 1 号鼠标键
<Key-a>按下 a 键
<a> 或 a<Key-a> 的简写
<Motion>鼠标移动了, 无论按键是否有按下
<B1-Motion>1 号键按下时鼠标移动了

进行绑定的脚本会访问有关事件的各方面信息,例如当事件发生时鼠标所在的位置

bind . <Motion> {puts "pointer at %x,%y"}

创建一个组件时,一个与该组件同名的 tcl 命令也就创建了,你可以调用这个命令来与该组件通信。

组件命令的第一个参数是某一个选项,后面的其他参数是该选项所需的变量。这个脚本中第一条组件命令是让按钮闪烁。(您不一定能看到按钮闪烁,这和计算机系统的显示方案有关。)

第二条组件命令让按钮组件调用它自己的-command选项,就如同您用鼠标单击按钮一样,从而实现回车后执行阶乘计算。

不同类型的组件的组件命令支持不同的选项集,但不同类型之间也有很多选项是相似的。

例如,所有的组件都支持一个组件命令configure,用来修改组件的设置选项。

# 将输入组件背景改为黄色
.value configure -background yellow

# 让用户界面这个按钮无法响应
.calculate configure -state disbale
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值