SetTimer

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

SetTimer , Label, PeriodeOnOffDelete, 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 die meisten Parameter von anderen Befehlen auch, eine Variablenreferenz wie %MeinLabel% sein, um den Inhalt der Variable als Ziel zu verwenden.

[v1.1.01+]: Lässt man Label weg, wird standardmäßig A_ThisLabel verwendet. Zum Beispiel könnte SetTimer,, Off innerhalb einer Timer-Subroutine verwendet werden, um den Timer zu deaktivieren. SetTimer,, 1000 wiederum 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, deren Parameterliste keine Pflichtparameter aufweist (siehe Funktionsbeispiel), oder eine einzelne Variablenreferenz 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 einen leeren Wert ergibt, wird als Fehler eingestuft. Dieser Parameter muss entweder einen nicht-leeren Wert enthalten oder komplett weggelassen werden.

PeriodeOnOffDelete

On: Reaktiviert einen zuvor deaktivierten Timer mit seiner 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, es sei denn, es wird eine Variable oder ein Ausdruck genutzt, dann werden alle Nachkommastellen ignoriert. Dessen absoluter Wert darf nicht größer als 4294967295 ms (49,7 Tage) sein.

Standardwert: Wenn dieser Parameter leer ist und:
1) der Timer nicht existiert, wird er mit einer Periode von 250 erstellt.
2) der Timer bereits existiert, wird er aktiviert und auf seine frühere Periode zurückgesetzt, sofern keine Priorität angegeben ist.

Priorität

Dieser optionale Parameter ist ein Integer zwischen -2147483648 und 2147483647 (oder ein Ausdruck), um die Thread-Priorität des Timers zu bestimmen. Lässt man diesen Parameter weg, wird standardmäßig 0 verwendet. Siehe Threads für weitere Details.

Um die Priorität eines vorhandenen Timers zu ändern, ohne ihn anderweitig zu beeinflussen, lassen Sie 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 von 1 bis 10 äquivalent zu 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 nicht zum erwarteten Zeitpunkt ausgeführt wird, wenn folgende Bedingungen auftreten:

  1. Andere Anwendungen belasten die CPU ziemlich stark.
  2. Die Timer-Subroutine selbst läuft noch nach Ablauf der Timer-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.

Timer funktionieren zwar, wenn das Skript suspendiert ist, aber nicht, 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 Tray-Menü oder eine Menüleiste).

Da Timer vorübergehend die aktuelle Aktivität des Skripts unterbrechen, sollten ihre Subroutinen kurzgehalten 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).

Jede via SetTimer gestartete Subroutine verwendet vorerst die Standardwerte von Einstellungen wie SendMode. Diese Standardwerte können im automatischen Ausführungsbereich geändert werden.

Wenn die Hotkey-Reaktionszeit von entscheidender Bedeutung ist (z. B. bei Videospielen) 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.

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

Beispiele

Schließt unerwünschte Fenster, sobald sie erscheinen.

#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

Wartet auf ein bestimmtes Fenster und alarmiert danach den Benutzer.

#Persistent
SetTimer, Alarm1, 500
return

Alarm1:
if not WinExist("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

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_eingaben > 0) ; Da SetTimer bereits gestartet wurde, wird stattdessen der Tastendruck protokolliert.
{
    winc_eingaben += 1
    return
}
; Ansonsten ist das der erste Tastendruck einer neuen Serie. Zählung wird
; auf 1 gesetzt und der Timer gestartet:
winc_eingaben := 1
SetTimer, TasteWinC, -400 ; Wartet auf weitere Eingaben innerhalb eines 400-Millisekunden-Zeitfensters.
return

TasteWinC:
if (winc_eingaben = 1) ; Die Taste wurde einmal gedrückt.
{
    Run, m:\  ; Öffnet einen Ordner.
}
else if (winc_eingaben = 2) ; Die Taste wurde zweimal gedrückt.
{
    Run, m:\multimedia  ; Öffnet einen anderen Ordner.
}
else if (winc_eingaben > 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_eingaben := 0
return

Ein einfacher Zähler. Verwendet eine Funktion als Timer-Subroutine.

#Persistent
SetTimer, Tick, 1000

Tick()
{
    static count := 0
    ToolTip % count++
}

Ein komplexerer Zähler. Verwendet eine Methode als Timer-Subroutine.

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 eine Referenz 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 eine reine Variablenreferenz.
        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: