http://blog.csdn.net/dulixin/archive/2008/05/04/2383555.aspx
1、after
after主要用于要延迟一段时间再执行脚本,update主要用于处理挂起的事件和回调,vwait可以跟踪一个变量的修改。
名称
after - 等待一段时间后再执行命令
语法
after ms
after ms ?script script script ...?
after cancel id
after cancel script script script ...
after idle ?script script script ...?
after info ?id?
描述
这个命令用来延迟程序执行或者在后台执行命令,它有几种形式,取决于这个命令的第一个参数:
after ms
Ms必须是个整型数据,以毫秒为单位。这个命令是休眠ms毫秒后返回。当这个命令在休眠的时候应用程序不想赢任何事件。
after ms ?script script script ...?
这种形式的命令直接返回数值,但是会在ms毫秒后把一个Tcl命令作为事件处理来运行。这个命令在给出的时候就会被立刻执行.延迟命令就像concat命令格式的风格被连接起来,这个命令将在全局运行(脱离所有Tcl进程的上下文)。当运行延迟命令时产生错误就使用interp bgerror机制来报告错误。after命令返回一个可以使用after cancel来取消延迟命令的ID。
after cancel id
取消运行之前已经确定要运行的延迟命令。id指出了哪个延迟命令会被取消,之前必须有一个after命令返回的id。如果给出id的命令已经运行那么after cancel就没有作用。
after cancel script script ...
这个命令也可以取消一个延迟命令的执行,这个script参数被使用空格分隔连接在一起(就像concat命令的风格),如果有一个没有执行的命令和要取消的命令相同,这个命令就被取消运行,如果没有和要取消命令相同的命令那么after cancel就没有作用.
after idle script ?script script ...?
把script参数使用空格分隔连接在一起(就像concat命令的风格),并且当空闲回调后安排最终的脚本稍后会被执行。这个脚本会立刻运行,接着会进入事件循环而且进程中没有事件。这个命令返回一个可以使用after cancel取消的延迟命令ID。当运行延迟命令时产生错误就使用interp bgerror机制来报告错误。
after info ?id?
这个命令返回当前存在的事件句柄。如果没有id参数没有提供,这个命令返回所有被after命令创建的事件句柄。如果提供了id,指定一个存在的句柄,这个句柄必须是之前使用after命令返回的参数而且必须不能已经触发或者取消。这个命令返回一个包含两个元素的列表,第一个元素是命令相关的id,第二个元素指示事件句柄类型是idle还是timer。
after ms和after idle形式的命令假定应用程序是事件驱动的,直到应用程序进入了事件循环,延迟命令才会被执行.在不是一般事件驱动的应用程序当中,比如tclsh,可以使用vwait或者update命令进入事件循环.
示例
这个例子定义了一个命令使tcl空闲N秒:
proc sleep {N} { after [expr {int($N * 1000)}]}
下面的脚本使wake_up在8个小时后运行(在这个时间事件循环被激活):
after [expr {1000 * 60 * 60 * 8}] wake_up
下面的命令可以被用于一步一步地方式做长时间运行的计算(就像这里描述的::my_calc::one_step,假设返回一个布尔数值来标志其它的步骤是否在执行).既然计算本身需要被排序所以可以逐步工作.这个技巧在使用的时候需要十分小心,需要避免事件循环杯进程管理给饿死(当下一个步骤去做一个已经触发的时间事件时正好事件队列被耗尽),在你做一个很慢的任务时,想确认一个TK GUI是否还有响应的时候非常有用.
proc doOneStep {} { if {[::my_calc::one_step]} { after idle [list after 0 doOneStep] }}doOneStep
after有几种形式,使用比较灵活。
最简单的形式,间隔一定时间后再运行脚本:
% after 5000
上面的命令就是间隔5秒钟后再继续运行脚本,这在等待其它设备处理时比较有效。
间隔一段时间后执行一条命令:
% set a a
a
% after 5000 set a b
after#1
间隔5秒钟后执行命令set a b,如果等待5秒钟后再查看$a的值就变成b了。需要注意的是,在tcl中,时间循环并没有开启,而tk中事件循环总是活动的,所以在tcl脚本中使用时需要非常小心,可能你需要的值在5秒钟后并没有改变,这里就需要使用到两个命令update和vwait,update命令可以时解释器去处理挂起的事件,vwait可以等待一个变量到修改为止,下面举例说明:
如果在5秒钟之后使用查看变量a里面的值:
% puts $a
a
还是a,并没有修改为b,那么这个时候使用update:
% update
% puts $a
b
上面的方法可能在实际使用时并没有意义,也许脚本的编写者是想在tcl中精确的控制脚本的执行时间,那也没有问题,可以使用vwait来操作,在时间间隔的期限内使用vwait可以使命令在精确的时间间隔时执行:
% set a a
a
% after 5000 set a b
after#1
% vwait a
%
会等待到第5秒钟执行赋值命令。
如果注册了一条命令在某个时间执行,也可以取消这个命令的执行,使用after cancel命令,这个命令有两种形式,既可以输入要取消命令的ID,也可以使用该命令本身来取消。
如想要取消ID为after#1的命令:
% after cancel after#1
如果ID为after#1的命令存在就去掉这个命令的注册,如果不存在就什么都不发生。
取消一个命令体:
% after 5000 set a c
after#2
% after cancel set a c
以上命令就会取消set a c的事件注册,如果不存在这个命令就什么都不发生。
显示目前注册的after事件或者某个after事件的详细信息:
直接使用after info命令来显示所有的after事件:
% after 5000 set a b
after#1
% after 5000 set a c
after#2
% after info
after#2 after#1
如果需要知道after事件的详细信息,就需要使用具体的事件ID:
% after info after#1
{set a b} timer
2、update
名称
update - 处理挂起的事件和空闲回调
语法
update ?idletasks?
描述
这个命令用来给应用程序“更新”,进入事件循环直到所有挂起的事件和空闲回调都执行完毕。
如果指定idletasks,就不处理新的事件或错误,只有空闲回调被调用,这就导致操作被延迟了,就像显示更新和窗口设计,会被立刻执行。
当应用程序的状态发生变化和需要这些变化立刻显示时update idletasks命令是非常有用的,不用等待到脚本完成。多数显示更新被当作空闲回调来执行,所以update idletasks可以使它们运行。但是这里有一些更新只能在事件响应中发生,像窗口尺寸变化触发等,这些更新不会在update idletasks中发生。
当运行一个长的运算但是仍然想和应用程序交互时,update命令在脚本中非常有用。
示例
运行一个循环约一秒钟后停止:
set x 1000
set done 0
after 1000
set done 1
while {!$done} {
#一个无聊的例子
set x [expr {log($x) ** 2.8}]
#测试时间是否到
update
}
3、vwait
名称
vwait - 一直等待直到一个变量被修改为止
语法
vwait varName
描述
这个命令进入Tcl事件循环,Tcl将会一直处理事件直到变量varName被修改为止,一旦varName被修改了,vwait命令将会立刻返回,varName必须是一个全局范围变量。(要么是一个全局变量,要么带有完全的名字空间路径)。
在一些情况下在varName被修改后vwait命令可能不会立刻返回,如果设置varName的事件句柄没有完成,那么vwait命令就不会立刻返回。例如,如果一个事件句柄设置varName,然后它自己调用vwait去等待一个不同的变量,这样的话有可能需要经过长时间后才能返回。在这种情况下最高堆栈层的vwait命令阻塞,等待事件句柄完成,所以不能返回。
示例
运行事件循环直到一些事件调用exit。
vwait forever
在连接一个服务器套接字时等待5秒钟,否则关闭套接字继续运行脚本。
# Initialise the stateafter 5000 set state timeoutset server [socket -server accept 12345]proc accept {args} { global state connectionInfo set state accepted set connectionInfo $args}
# Wait for something to happenvwait state
# Clean up events that could have happenedclose $serverafter cancel set state timeout
# Do something based on how the vwait finished...switch $state { timeout { puts "no connection on port 12345" } accepted { puts "connection: $connectionInfo" puts [lindex $connectionInfo 0] "Hello there!" }}