# SetTimer

以一个指定的时间间隔来自动重复地启动子程序。

SetTimer, Label [, Period|On|Off, Priority]

#### 参数

Label | 欲跳转的标签或热键标签的名称，它使 Lable 下面的命令被执行直到遇上 Return 或 Exit。与几乎所有其他命令的参数一样，Label 可以是一个变量引用比如 %MyLabel%，在这种情况下变量中存储的名称会被作为目标使用。
Period|On|Off | On: 重新启用一个在它的先前 period (周期)中被禁用的定时器。如果不存在定时器，则创建它(默认周期为 250)。如果存在定时器但先前被设置成了 run-only-once 模式，它仍然只运行一次。 Off: 禁用一个已存在的定时器。 Period: 使用这个参数作为 Label 子程序上一次开始后必须经过的近似 毫秒数来创建或更新一个定时器。在这段时间过后，将再次运行 Label （除非它仍在继续上一次运行）。定时器将被自动启用。要防止这种情况，可以随后立即再一次调用此命令，将此参数指定为 OFF。 如果此参数为空并且: 1) 定时器不存在：那么将创建一个周期为 250 的定时器。 2) 定时器已存在：那么将启用定时器，并重设它先前的 period，除非指定了 Priority。 Run only once [v1.0.46.16+]: 用一个负的 Period 来表示定时器只能运行一次。例如，指定 -100 将在 100ms 后运行定时器，然后就像使用了 SetTimer, Label, Off 那样禁用定时器。
Priority | 这个可选参数是一个介于 -2147483648 和 2147483647 之间的整数（或一个表达式），用来表示此定时器的线程优先级。如果省略将视为 0。详见线程。 要改变一个已有定时器的优先级而不在任何其他方面影响它，只要将此参数前面的那些参数都留空。

#### 注意

定时器很有用，因为它们是异步运行的，这意味着即使当脚本正在等待一个窗口，显示一个对话框，或忙于其他任务时，定时器也将按指定的频率（间隔）运行。它们的许多应用实例包括当用户闲置时(如 %A_TimeIdle% 反映的那样)采取某些行动或者在不需要的窗口出现时关闭它们。

尽管定时器会给人以脚本同时运行多个任务的错觉，但实际并非如此。而是定时的子程序被作为其他线程来处理：它们能中断别的线程或被另一个线程打断，比如热键子程序。详见线程。

无论一个定时器是被创建，重新启用，还是更新为一个新的 period，其子程序都不会马上运行；它的 period 时间必须先到期。如果你想让定时器的首次执行马上开始，可用 Gosub 来执行定时器的子程序（不过这种方式不会像定时器自身那样开启一个新线程；所以像 SendMode 这样的设置就不会以它们的默认值启动了）。

如果 SetTimer 被用在一个已存在的定时器上且第二个参数是一个数字或单词 ON(或它被省略)，定时器内部的“上次被运行时间”将被重置为当前时间；换句话说，必须在定时器经过它的整个周期后，其子程序才会再次运行。

定时器精度: 由于操作系统的时间记录系统的间隔原因, 周期 通常最接近10或15.6毫秒的倍数(取决于硬件和安装的驱动)。比如，一个在1和10之间(包括10)的周期在Windows NT/2000/XP下通常等于10或15.6(Windows 9x下约为55ms)。通过Loop+Sleep可以获得更短的延时，请看示例：DllCall+timeBeginPeriod+Sleep.

定时器在下列情况中可能无法按指定频率运行：

1. 其它应用程序使 CPU 负担过重。
2. 定时器的子程序本身花费了比它的周期更长的时间来运行，或有太多相抵触的定时器（调整 SetBatchLines 可能会有所帮助）。
3. 定时器被另一个线程，即另一个定时的子程序、热键子程序或者自定义菜单项打断(这可以通过 Critical 避免)。如果发生了这种情况且打断线程花了很长时间才结束，那么实际上被打断的定时器在这段时间中将被禁用。不过，其它的定时器对打断首个定时器的线程进行中断，仍可继续运行。
4. 脚本由于 Critical 或 Thread Interrupt/Priority 而不可中断。在此时间内，定时器不会运行。之后，当脚本可再次中断时，延误的定时器会尽快运行一次然后恢复到它的正常运作。

由于定时器靠临时中断脚本的当前活动来运作，所以它们的子程序应保持简短（以便它们迅速完成），无论何时都不适宜有很长的中断。

一个脚本运行期间持续生效的定时器通常应在自动执行部分创建。相比之下，临时定时器经常会被它的子程序禁用（请看本页底部的示例）。

每当一个定时的子程序运行时，它的设置比如 SendMode 都会以默认值重新开始。这些默认值可在自动执行部分修改。

虽然定时器会在脚本挂起时运作，但如果当前线程的 "Thread NoTimers" 正生效或者每当线程被暂停时，它们是不会运行的。另外，在用户浏览脚本的某个菜单时（如托盘图标菜单或菜单栏）定时器也不会运作。

如果热键的响应时间很重要（比如游戏中）且脚本包含的定时器子程序执行时间会超过 5 ms，那么可以使用如下命令来避免 15 ms 的延迟。否则如果热键正好在一个定时器线程处于它的不可中断周期时被按下，这个延迟就会发生：

    Thread, interrupt, 0  ;使所有线程始终可中断。

如果定时器在它的子程序正运行时被禁用，该子程序会继续运行直到完成。

KeyHistory 功能会显示存在多少个定时器，当前启用了多少个。

定时器的周期不可大于 4294967295 毫秒(49.7 天)。

要让脚本持续运行，比如那些只包含了定时器的脚本，请用 #Persistent。

#### 相关命令

Gosub, Return, Threads, Thread (command), Critical, IsLabel(), Menu, #Persistent

#### 示例

    ;例 1: 当不需要的窗口出现时将其关闭：
    #Persistent
    SetTimer, CloseMailWarnings, 250
    return

    CloseMailWarnings:
    WinClose, Microsoft Outlook, A timeout occured while communicating
    WinClose, Microsoft Outlook, A connection to the server could not be established
    return

    ;例 2: 等待一个特定的窗口出现，然后通知用户：
    #Persistent
    SetTimer, Alert1, 500
    return

    Alert1:
    IfWinNotExist, Video Conversion, Process Complete
        return
    ;否则:
    SetTimer, Alert1, Off  ;即定时器在此处将自己关闭。
    SplashTextOn, , , 视频转换已完成。
    Sleep, 3000
    SplashTextOff
    return

    ;例 3: 检测热键的单击、双击和三次按击。
    ;这允许热键可以按你按键的次数来执行不同的操作：
    #c::
    if winc_presses > 0 ; SetTimer 已经启动，所以我们记录按键。
    {
        winc_presses += 1
        return
    }
    ;否则，这是新一系列按键的首次按键。将计数设为 1 并启动定时器：
    winc_presses = 1
    SetTimer, KeyWinC, 400 ;在 400 毫秒内等待更多的按键。
    return

    KeyWinC:
    SetTimer, KeyWinC, off
    if winc_presses = 1 ;该键已按过一次。
    {
        Run, m:\  ;打开一个文件夹。
    }
    else if winc_presses = 2 ;该键已按过两次。
    {
        Run, m:\multimedia  ;打开一个不同的文件夹。
    }
    else if winc_presses > 2
    {
        MsgBox, 检测到三次或更多次点击。
    }
    ;不论上面哪个动作被触发，将计数复位以备下一系列的按键：
    winc_presses = 0
    return

翻译：bu45gande 修正：天堂之门 menk33@163.com 2008年12月18日