SetTimer

Lässt eine Subroutine automatisch und wiederholend in einem angegebenen Zeitintervall laufen.

SetTimer [, Label, Periode|On|Off|Delete, Priorität]

Parameter

Label

Name des Labels oder Hotkey-Labels, der angesprungen werden soll, um die Befehle unterhalb von Label auszuführen, bis ein Return oder Exit erreicht wurde. Label kann, wie Parameter und die meisten anderen Befehle auch, einen Variablenverweis wie %MeinLabel% enthalten, um den gespeicherten Namen in der Variable als Ziel zu verwenden.

[v1.1.01+]: Fehlt das Label, wird stattdessen A_ThisLabel verwendet. Zum Beispiel könnte SetTimer,, Off innerhalb einer Timer-Subroutine verwendet werden, um den Timer zu deaktivieren. SetTimer,, 1000 wiederrum würde entweder die Periode des aktuellen Timers ändern oder einen neuen Timer mit dem Label der aktuell laufenden Subroutine erstellen. [v1.1.24+]: Wenn A_ThisLabel leer ist, aber der aktuelle Thread durch einen Timer gestartet wurde, wird dieser Timer verwendet. Das ist besonders für Timer nützlich, die Funktionen oder Funktionsobjekte starten müssen.

[v1.1.20+]: Wenn es kein gültiger Labelname ist, kann dieser Parameter der Name einer Funktion sein, oder ein einzelner Variablenverweis mit einem Funktionsobjekt. Zum Beispiel SetTimer %funkobj%, 1000 oder SetTimer %funkobj, 1000. Andere Ausdrücke, die Objekte zurückgeben, werden zurzeit nicht unterstützt. Mehr dazu finden Sie im Beispiel weiter unten.

Hinweis: [v1.1.24+]: Die Übergabe einer leeren Variable oder eines Ausdrucks, der zu einem leeren Wert führt, wird als Fehler eingestuft. Dieser Parameter darf weder leer sein noch fehlen.

Periode|On|Off|Delete

On: Reaktiviert einen zuvor deaktivierten Timer mit ihrer früheren Periode. Falls der Timer noch nicht vorhanden ist, wird er erstellt (mit einer Standardperiode von 250). Der Timer wird außerdem zurückgesetzt. Wenn ein Timer bereits vorhanden ist, der zuvor im Nur-Einmal-Laufen-Modus gestartet wurde, wird er auch dieses Mal nur einmal ausgeführt.

Off: Deaktiviert einen vorhandenen Timer.

Delete [v1.1.20+]: Deaktiviert und entfernt einen vorhandenen Timer. Wenn der Timer mit einem Funktionsobjekt verbunden ist, wird das Objekt freigegeben. Nur das Ausschalten eines Timers wird das Objekt nicht freigeben.

Periode: Erstellt oder aktualisiert einen Timer. Der absolute Wert von diesem Parameter ist die ungefähre Zeit in Millisekunden, die ablaufen muss, bevor der Timer ausgeführt wird. Der Timer wird dabei automatisch aktiviert und zurückgesetzt. Man kann den Timer so einstellen, dass er sich automatisch wiederholt oder nur einmal läuft:

Periode muss ein Integer sein. Verwendet man eine Variable oder einen Ausdruck, werden Nachkommastellen ignoriert. Ihr absoluter Wert darf nicht größer sein als 4294967295 ms (49,7 Tage).

Default: Wenn dieser Parameter leer ist und:
1) der Timer nicht existiert, wird der Timer mit einer Periode von 250 erstellt.
2) der Timer bereits vorhanden ist, wird er aktiviert und seine frühere Periode wiederhergestellt, sofern eine Priorität noch nicht angegeben wurde.

Priorität

Dieser optionale Parameter ist ein Integer zwischen -2147483648 und 2147483647 (oder ein Ausdruck), um die Thread-Priorität des Timers zu bestimmen. Fehlt dieser Parameter, gilt standardmäßig 0. Siehe Threads für weitere Details.

Um die Priorität eines vorhandenen Timers zu ändern, ohne ihn anderweitig zu beeinflussen, lässt man den Parameter vor diesem leer.

Bemerkungen

Timer sind nützlich, weil sie asynchron laufen - das heißt, dass sie in einem bestimmten Intervall (Frequenz) ausgeführt werden, auch dann, wenn das Skript auf ein Fenster wartet, ein Dialogfenster anzeigt oder mit einer anderen Aufgabe beschäftigt ist. Unter anderem kann der Timer verwendet werden, um eine Aktion bei Abwesenheit des Benutzers durchzuführen (in Verbindung mit A_TimeIdle) oder um unerwünschte Fenster sofort wieder zu schließen, wenn sie erscheinen.

Timer erzeugen nur die Illusion, dass das Skript mehrere Aufgaben gleichzeitig durchführen kann. In Wirklichkeit werden zeitgesteuerte Subroutinen genauso wie andere Threads behandelt: sie können unterbrechen oder von anderen Threads, wie z. B. eine Hotkey-Subroutine, unterbrochen werden. Siehe Threads für weitere Details.

Die Subroutine eines erstellten, reaktivierten oder mit einer neuen Periode versehenen Timers wird nicht sofort ausgeführt; zuerst muss seine angegebene Periode verstreichen. Wenn der Timer sofort beginnen soll, müssen Sie Gosub zum Ausführen der Timer-Subroutine verwenden (allerdings wird das keinen neuen Thread starten, wie es der Timer selbst machen würde; demzufolge werden Einstellungen wie SendMode nicht mit ihren Standardwerten beginnen).

Zurücksetzen: Wenn SetTimer auf einen bereits vorhandenen Timer angewendet wird und der 2. Parameter eine Nummer oder das Wort ON ist (oder weggelassen wird), wird der Timer zurückgesetzt; das heißt, dass seine Periode einmal komplett ablaufen muss, bevor seine Subroutine erneut starten kann.

Genauigkeit des Timers: Durch die Granularität (Ungenauigkeit) der Zeiterfassung im Betriebssystem wird Periode möglicherweise auf das nächstmögliche Vielfache von 10 oder 15.6 Millisekunden aufgerundet (abhängig vom Typ der installierten Hardware und Treiber). In Windows 2000/XP ist eine Periode zwischen 1 und 10 gleichbedeutend mit 10 oder 15.6. Eine kürzere Verzögerung kann mittels Loop+Sleep erreicht werden, wie bei DllCall+timeBeginPeriod+Sleep gezeigt.

Zuverlässigkeit: Es kann sein, dass ein Timer unregelmäßig läuft, wenn folgende Bedingungen auftreten:

  1. Andere Anwendungen belasten die CPU ziemlich stark.
  2. Die Timer-Subroutine braucht länger als die angebende Periode oder es gibt zu viele konkurrierende Timer (das Ändern von SetBatchLines kann helfen).
  3. Der Timer wurde von einem anderen Thread unterbrochen, dazu zählen andere zeitgesteuerte Subroutinen, Hotkey-Subroutinen oder benutzerdefinierte Menüpunkte (kann mit Critical verhindert werden). Falls das passiert und der unterbrechende Thread lange Zeit zum Beenden braucht, wird der unterbrochene Timer für diese Dauer deaktiviert. Allerdings werden alle anderen Timer weiterlaufen, indem sie den Thread unterbrechen, der den ersten Timer unterbrochen hat.
  4. Ein Skript kann nicht unterbrochen werden, wenn man Critical oder Thread Interrupt/Priority verwendet. In solchen Zeiten werden Timer nicht laufen. Wenn das Skript später wieder unterbrochen werden kann, wird jeder überfällige Timer so bald wie möglich einmal ausgeführt und danach normal fortgesetzt.

Zwar funktionieren Timer auch, wenn das Skript gesperrt ist, allerdings werden sie nicht laufen, wenn Thread NoTimers im aktuellen Thread vorhanden ist oder wenn ein Thread pausiert wurde. Darüber hinaus werden sie nicht funktionieren, wenn der Benutzer in einem der Skriptmenüs navigiert (wie z. B. das Infobereichsmenü oder eine Menüleiste).

Da Timer vorübergehend die aktuelle Aktivität des Skripts unterbrechen, sollten ihre Subroutinen kurz gehalten werden (so dass sie schnell zum Ende kommen), wann immer eine lange Unterbrechung unerwünscht ist.

Sonstige Bemerkungen: Timer, die die ganze Zeit laufen sollen, sollten üblicherweise im automatischen Ausführungsbereich erstellt werden. Dagegen deaktivieren sich temporäre Timer oft mit ihren eigenen Subroutinen (siehe Beispiele weiter unten).

Immer wenn eine zeitgesteuerte Subroutine gestartet wird, beginnt sie mit den Standardeinstellungen von Befehlen wie SendMode. Diese Standardeinstellungen können im automatischen Ausführungsbereich geändert werden.

Wenn die Hotkey-Reaktionszeit von entscheidender Bedeutung ist (z. B. bei Spielen) und das Skript bestimmte Timer enthält, deren Subroutinen länger als 5 ms zum Ausführen benötigen, dann sollte der folgende Befehl verwendet werden, um eine mögliche Verzögerung von 15 ms zu unterbinden. So eine Verzögerung würde ansonsten auftreten, wenn ein Hotkey exakt zu dem Zeitpunkt gedrückt wird, wo ein Timer-Thread in seiner unterbrechungsfreien Phase ist:

Thread, interrupt, 0  ; Macht alle Threads jederzeit unterbrechbar.

Deaktiviert man einen Timer, während seine Subroutine noch läuft, wird diese Subroutine bis zu ihrem Ende fortgesetzt.

Die KeyHistory-Funktion zeigt, wie viele Timer vorhanden und wie viele zurzeit aktiviert sind.

Um ein Skript dauerhaft laufen zu lassen -- z. B. ein Skript, das ausschließlich Timer enthält -- ist es erforderlich, #Persistent zu verwenden.

Siehe auch

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

Beispiele

; Beispiel #1: Schließt unerwünschte Fenster, sobald sie auftauchen:
#Persistent
SetTimer, MailWarnungenSchließen, 250
return

MailWarnungenSchließen:
WinClose, Microsoft Outlook, Während der Kommunikation mit dem Server wurde das Zeitlimit überschritten
WinClose, Microsoft Outlook, Es konnte keine Verbindung aufgebaut werden
return

 

; Beispiel #2: Wartet auf ein bestimmtes Fenster und alarmiert danach den Benutzer:
#Persistent
SetTimer, Alarm1, 500
return

Alarm1:
IfWinNotExist, Video-Konvertierung, Prozess abgeschlossen
    return
; Ansonsten:
SetTimer, Alarm1, Off  ; d. h. der Timer deaktiviert sich selbst.
SplashTextOn, , , Die Video-Konvertierung wurde abgeschlossen.
Sleep, 3000
SplashTextOff
return

 

; Beispiel #3: Erkennt, ob ein Hotkey einmal, zweimal oder dreimal gedrückt wurde. Dadurch
; kann ein Hotkey eine unterschiedliche Operation durchführen,
; je nachdem, wie oft er gedrückt wurde:
#c::
if winc_anzahl > 0 ; Da SetTimer bereits gestartet wurde, wird stattdessen der Tastendruck protokolliert.
{
    winc_anzahl += 1
    return
}
; Ansonsten ist das der erste Tastendruck einer neuen Serie. Zählung wird
; auf 1 gesetzt und der Timer gestartet:
winc_anzahl = 1
SetTimer, TasteWinC, -400 ; Wartet bis zu 400 Millisekunden, dass der Hotkey nochmal gedrückt wird.
return

TasteWinC:
if winc_anzahl = 1 ; Die Taste wurde einmal gedrückt.
{
    Run, m:\  ; Öffnet einen Ordner.
}
else if winc_anzahl = 2 ; Die Taste wurde zweimal gedrückt.
{
    Run, m:\multimedia  ; Öffnet einen anderen Ordner.
}
else if winc_anzahl > 2
{
    MsgBox, Drei oder mehr Klicks erkannt.
}
; Unabhängig von der zuvor ausgelösten Aktion wird die Zählung zurückgesetzt,
; um die nächste Serie von Tastendrücken vorzubereiten:
winc_anzahl = 0
return

 

; Beispiel #4: Eine Methode als Timer-Subroutine verwenden.

counter := new SecondCounter
counter.Start()
Sleep 5000
counter.Stop()
Sleep 2000

; Eine Beispiel-Klasse zum Zählen der Sekunden...
class SecondCounter {
    __New() {
        this.interval := 1000
        this.count := 0
        ; Tick() hat einen impliziten Parameter "this", der ein Verweis auf
        ; das Objekt ist, daher müssen wir eine Funktion erstellen, die
        ; "this" und die aufzurufende Methode voneinander trennt:
        this.timer := ObjBindMethod(this, "Tick")
    }
    Start() {
        ; Bekannte Einschränkung: SetTimer benötigt einen reinen Variablenverweis.
        timer := this.timer
        SetTimer % timer, % this.interval
        ToolTip % "Counter gestartet"
    }
    Stop() {
        ; Um den Timer auszuschalten, müssen wir dasselbe Objekt erneut übergeben:
        timer := this.timer
        SetTimer % timer, Off
        ToolTip % "Counter stoppt bei " this.count
    }
    ; In diesem Beispiel ruft der Timer diese Methode auf:
    Tick() {
        ToolTip % ++this.count
    }
}

Tipps bezüglich des oberen Beispiels: