您的位置:首页 > 大数据 > 人工智能

tcl/tk详解——after、update和vwait

2013-05-10 10:12 204 查看
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!" }}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: