SetTimer

Registriert eine Subroutine, die automatisch und wiederholt in einem bestimmten Zeitintervall gestartet wird.

SetTimer , Label, PeriodeOnOffDelete, Priorität

Parameter

Label

Name eines Labels, Hotkey-Labels oder Hotstring-Labels, zu dem gesprungen werden soll, um alle Befehle unterhalb von Label bis zu einem Return oder Exit auszuführen. 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+]: Wenn Label weggelassen wird, wird standardmäßig A_ThisLabel verwendet. Zum Beispiel kann SetTimer,, Off innerhalb einer Timer-Subroutine verwendet werden, um den Timer zu deaktivieren, während SetTimer,, 1000 entweder die Periode des aktuellen Timers ändert oder einen neuen Timer mit dem Label der aktuell laufenden Subroutine erstellt. [v1.1.24+]: Wenn A_ThisLabel leer ist, aber der aktuelle Thread von einem Timer gestartet wurde, wird dieser Timer verwendet. Dies ist besonders nützlich für Timer, die Funktionen oder Funktionsobjekte starten müssen.

[v1.1.20+]: Dieser Parameter kann auch der Name einer Funktion ohne Pflichtparameter sein, wenn kein Label mit diesem Namen existiert, wie in Beispiel #4, oder eine einzelne Variablenreferenz mit einem Funktionsobjekt, wie in Beispiel #5. Andere Ausdrücke, die Objekte zurückgeben, werden zurzeit nicht unterstützt.

Hinweis: In [v1.1.24+] wird die Übergabe einer leeren Variable oder eines Ausdrucks, der einen leeren Wert zurückgibt, als Fehler gewertet. Dieser Parameter muss entweder einen nicht-leeren Wert enthalten oder ganz weggelassen werden.

PeriodeOnOffDelete

Wenn leer oder weggelassen und der Timer nicht existiert, wird er mit einer Periode von 250 erstellt. Wenn leer oder weggelassen und der Timer bereits existiert, wird er aktiviert und auf seine frühere Periode zurückgesetzt, sofern keine Priorität angegeben ist. Andernfalls geben Sie Folgendes an:

Periode: Erstellt oder aktualisiert einen Timer unter Verwendung des Absolutwertes dieses Parameters als ungefähre Zeit in Millisekunden, die ablaufen muss, bevor der Timer ausgeführt wird. Der Timer wird automatisch aktiviert und zurückgesetzt. Wenn Periode positiv ist, wiederholt sich der Timer automatisch, bis er im Skript explizit deaktiviert wird. [v1.0.46.16+]: Wenn Periode negativ ist, wird der Timer nur einmal ausgeführt. Zum Beispiel wird durch Angabe von -100 der Timer nach 100 ms einmal ausgeführt und dann deaktiviert, als wäre SetTimer, Label, Off verwendet worden. [v1.1.24+]: Wenn Label ein via Skript erstelltes Objekt ist (also keine Funktion oder Label), wird der Timer automatisch gelöscht, nachdem die Timerfunktion ihren Wert zurückgegeben hat, es sei denn, der Timer wurde reaktiviert. Dadurch kann das Objekt freigegeben werden, wenn es vom Skript nicht mehr benötigt wird, was aber auch bedeutet, dass die Periode und Priorität des Timers verworfen werden.

Periode muss ein Integer sein, es sei denn, es wird eine Variable oder ein Ausdruck verwendet, dann werden alle Dezimalstellen ignoriert. Der Absolutwert darf nicht größer als 4294967295 ms (49,7 Tage) sein.

On: Reaktiviert einen zuvor deaktivierten Timer mit seiner früheren Periode. Wenn der Timer nicht existiert, wird er erstellt (mit einer Standardperiode von 250). Der Timer wird auch zurückgesetzt. Wenn der Timer existiert, aber zuvor auf den Nur-Einmal-Ausführen-Modus (siehe oben) gesetzt wurde, wird er auch dieses Mal nur einmal ausgeführt.

Off: Deaktiviert einen existierenden Timer.

Delete [v1.1.20+]: Deaktiviert und löscht einen existierenden Timer. Wenn der Timer mit einem Funktionsobjekt verbunden ist, wird das Objekt freigegeben. Die Deaktivierung allein führt nicht zur Freigabe des Objekts.

Priorität

Wenn leer oder weggelassen, wird standardmäßig 0 verwendet. Andernfalls geben Sie einen Integer zwischen -2147483648 und 2147483647 (oder einen Ausdruck) an, um die Thread-Priorität des Timers zu bestimmen. Einzelheiten finden Sie unter Threads.

Um die Priorität eines existierenden Timers zu ändern, ohne ihn anderweitig zu beeinflussen, lassen Sie den Parameter vor diesem leer.

Bemerkungen

Timer sind nützlich, weil sie asynchron laufen, d.h. sie werden in einem bestimmten Intervall (Frequenz) ausgeführt, egal ob das Skript gerade auf ein Fenster wartet, ein Dialogfenster anzeigt oder mit einer anderen Aufgabe beschäftigt ist. Timer können u.a. verwendet werden, um eine Aktion während der Abwesenheit des Benutzers auszuführen (in Verbindung mit A_TimeIdle) oder um unerwünschte Fenster sofort wieder zu schließen, wenn sie erscheinen.

Timer erzeugen nur die Illusion, als könne das Skript mehr als eine Aufgabe gleichzeitig ausführen. In Wirklichkeit werden zeitgesteuerte Subroutinen wie andere Threads behandelt: Sie können andere Threads, wie z.B. Hotkey-Subroutinen, unterbrechen oder von ihnen unterbrochen werden. Einzelheiten finden Sie unter Threads.

Jedes Mal, wenn ein Timer erstellt, reaktiviert oder mit einer neuen Periode aktualisiert wird, wird seine Subroutine nicht sofort ausgeführt; seine Periode muss zuerst ablaufen. Wenn die erste Ausführung des Timers sofort erfolgen soll, führen Sie seine Subroutine mit Gosub aus (dabei wird allerdings kein neuer Thread gestartet, wie es der Timer selbst tut, d.h. Einstellungen wie SendMode verwenden zunächst nicht ihre Standardwerte).

Zurücksetzen: Wenn SetTimer auf einen bereits existierenden Timer angewendet wird und der 2. Parameter eine Zahl oder das Wort ON ist (oder leer ist oder weggelassen wird), wird der Timer zurückgesetzt, d.h. seine Periode muss einmal komplett ablaufen, 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 mit Loop+Sleep erreicht werden, wie bei DllCall+timeBeginPeriod+Sleep gezeigt.

Zuverlässigkeit: Es ist möglich, dass ein Timer nicht zum erwarteten Zeitpunkt ausgeführt wird, wenn die folgenden Bedingungen zutreffen:

  1. Andere Anwendungen belasten die CPU ziemlich stark.
  2. Die Timer-Subroutine selbst läuft noch, nachdem die Timer-Periode abgelaufen ist, oder es gibt zu viele andere konkurrierende Timer (das Ändern von SetBatchLines kann helfen).
  3. Der Timer wurde von einem anderen Thread unterbrochen, z.B. von einer anderen zeitgesteuerten Subroutine, einer Hotkey-Subroutine oder einem benutzerdefinierten Menüpunkt (dies kann mit Critical verhindert werden). Wenn dies der Fall ist und der unterbrechende Thread lange Zeit zum Beenden braucht, wird der unterbrochene Timer für die Dauer der Unterbrechung deaktiviert. Alle anderen Timer laufen jedoch weiter, indem sie den Thread unterbrechen, der den ersten Timer unterbrochen hat.
  4. Das Skript ist durch Critical oder Thread Interrupt/Priority unterbrechungsfrei. Während dieser Zeit werden Timer nicht ausgeführt. Später, wenn das Skript wieder unterbrechbar ist, wird jeder überfällige Timer einmal so schnell wie möglich ausgeführt und dann wie geplant fortgesetzt.

Obwohl Timer auch laufen, wenn das Skript suspendiert ist, werden sie nicht ausgeführt, wenn Thread NoTimers für den aktuellen Thread wirksam ist oder wenn ein beliebiger Thread pausiert wird. Außerdem werden sie nicht ausgeführt, wenn der Benutzer durch eines der Menüs des Skripts navigiert (z.B. das Tray-Symbol-Menü oder eine Menüleiste).

Da Timer die laufende Skriptaktivität vorübergehend unterbrechen, sollten ihre Subroutinen kurz gehalten werden (so dass sie schnell zum Abschluss kommen), wenn eine lange Unterbrechung unerwünscht ist.

Sonstige Bemerkungen: Timer, die die ganze Zeit laufen, werden üblicherweise im automatischen Ausführungsbereich erstellt, während ein temporärer Timer sich oft durch seine eigene Subroutine selbst deaktiviert (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. in Videospielen) und Timer im Skript enthalten sind, deren Subroutinen länger als 5 ms zum Ausführen benötigen, verwenden Sie den folgenden Befehl, um eine mögliche Verzögerung von 15 ms zu vermeiden. Eine solche Verzögerung würde sonst auftreten, wenn ein Hotkey genau dann gedrückt wird, wenn sich ein Timer-Thread in seiner unterbrechungsfreien Phase befindet:

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

Wenn ein Timer deaktiviert wird, während seine Subroutine gerade läuft, wird diese Subroutine fertig ausgeführt.

KeyHistory zeigt an, wie viele Timer es gibt und wie viele gerade aktiv sind.

Um ein Skript dauerhaft laufen zu lassen - z.B. ein Skript, das nur Timer enthält - verwenden Sie #Persistent.

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 dann den Benutzer.

#Persistent
SetTimer, Alarm1, 500
return

Alarm1:
if not WinExist("Videokonvertierung", "Prozess abgeschlossen")
    return
; Andernfalls:
SetTimer, Alarm1, Off  ; d.h. der Timer deaktiviert sich selbst.
SplashTextOn, , , Die Videokonvertierung wurde abgeschlossen.
Sleep, 3000
SplashTextOff
return

Erkennt, ob ein Hotkey einmal, zweimal oder dreimal gedrückt wurde. Dadurch kann ein Hotkey eine andere Aktion ausführen, je nachdem, wie oft er gedrückt wurde.

#c::
if (winc_eingaben > 0) ; SetTimer bereits gestartet, also stattdessen den Tastendruck protokollieren.
{
    winc_eingaben += 1
    return
}
; Andernfalls ist das der erste Tastendruck einer neuen Serie. Zählung wird
; auf 1 gesetzt und der Timer gestartet:
winc_eingaben := 1
SetTimer, TasteWinC, -400 ; Auf weitere Eingaben innerhalb von 400 ms warten.
return

TasteWinC:
if (winc_eingaben = 1) ; Die Taste wurde einmal gedrückt.
{
    Run, m:\  ; Einen Ordner öffnen.
}
else if (winc_eingaben = 2) ; Die Taste wurde zweimal gedrückt.
{
    Run, m:\multimedia  ; Einen anderen Ordner öffnen.
}
else if (winc_eingaben > 2)
{
    MsgBox, Drei oder mehr Klicks erkannt.
}
; Egal welche obige Aktion ausgelöst wurde, Zählung zurücksetzen,
; 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 Beispielklasse zum Zählen von 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 % "Zähler gestartet"
    }
    Stop() {
        ; Um den Timer zu deaktivieren, dasselbe Objekt erneut übergeben:
        timer := this.timer
        SetTimer % timer, Off
        ToolTip % "Zähler ist bei " this.count " gestoppt"
    }
    ; In diesem Beispiel ruft der Timer diese Methode auf:
    Tick() {
        ToolTip % ++this.count
    }
}

Tipps zum obigen Beispiel: