{"id":55000498,"date":"2026-02-01T00:00:00","date_gmt":"2026-03-10T11:54:53","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=498"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Timer_ohne_Formular_mit_VBA_programmieren","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Timer_ohne_Formular_mit_VBA_programmieren\/","title":{"rendered":"Timer ohne Formular mit VBA programmieren"},"content":{"rendered":"<p><b>Unter Access kennt man eigentlich nur den Timer, den das Formular-Objekt mitbringt. Damit k&ouml;nnen wir ein Ereignis definieren, das in einem bestimmten Zeitintervall ausgel&ouml;st wird. Was aber, wenn wir einen Timer einmal au&szlig;erhalb des Kontexts eines Formulars ben&ouml;tigen? Dann erstellen wir uns einfach eine eigene Timer-Klasse. Dazu sind zwar ein paar Tricks und API-Funktionen n&ouml;tig, aber das soll kein Hindernis sein. Deshalb zeigen wir in diesem Beitrag im Detail, wie das gelingt und wie sich dieser Timer in der Praxis einsetzen l&auml;sst. Und im Gegensatz zum Formulartimer haben wir noch einen Vorteil: Wir k&ouml;nnen n&auml;mlich nicht nur einen, sondern beliebig viele Timer einsetzen und laufen lassen.<\/b><\/p>\n<h2>Klassischer Formular-Timer in Access<\/h2>\n<p>Wenn wir in Access einen Timer ben&ouml;tigen, ist das eigentlich nur &uuml;ber den Formular-Timer m&ouml;glich. Dazu f&uuml;gt man einem Formular das Ereignis <b>Bei Zeitgeber <\/b>hinzu und legt mit der Eigenschaft <b>Zeitgeberintervall <\/b>fest, in welchen Intervallen dieses Ereignis ausgel&ouml;st werden soll (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_498_003.png\" alt=\"Einfacher Formulartimer\" width=\"549,559\" height=\"422,0839\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Einfacher Formulartimer<\/span><\/b><\/p>\n<p>In der Ereignisprozedur tragen wir den Code ein, der beim Eintreten des Ereignisses <b>Form_Timer <\/b>ausgel&ouml;st werden soll. In diesem Fall aktualisieren wir alle 1.000 Millisekunden die Anzeige der Uhrzeit:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n    Me.txtUhrzeit = Time()\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Wenn der Timer nicht mehr ausgel&ouml;st werden soll, stellen wir die Eigenschaft <b>Zeitgeberintervall <\/b>per VBA auf <b>0 <\/b>ein:<\/p>\n<pre>Me.TimerInterval = 0<\/pre>\n<h2>Wenn mehr als ein Timer ben&ouml;tigt wird &#8230;<\/h2>\n<p>Ein Timer ist allerdings manchmal nicht ausreichend. Wenn man nicht mehrere Formulare mit einem Timer ausstatten will, muss man sich also eine andere L&ouml;sung &uuml;berlegen. Au&szlig;erdem gibt es auch Anwendungsf&auml;lle, in denen gerade kein Formular ge&ouml;ffnet ist, das den Timer zur Verf&uuml;gung stellen kann. Was ist zum Beispiel, wenn man regelm&auml;&szlig;ig einen bestimmten Status im Ribbon aktualisieren m&ouml;chte?<\/p>\n<p>F&uuml;r solche Anwendungsf&auml;lle stellen wir nun eine L&ouml;sung vor, mit der wir bis zu 100 Timer unabh&auml;ngig voneinander starten, ausl&ouml;sen und beenden k&ouml;nnen.<\/p>\n<p>Dazu ben&ouml;tigen wir eine Klasse, die den Timer selbst enth&auml;lt. Zudem ben&ouml;tigen wir ein paar Zeilen Code, um die Timer zu initialisieren und die dadurch ausgel&ouml;sten Ereignisse zu implementieren.<\/p>\n<h2>Die Klasse CLS_AMV_Timer<\/h2>\n<p>Die Klasse, welche die Timer bereitstellt, hei&szlig;t <b>CLS_AMV_Timer <\/b>und ist in Listing 1 zu finden. Sie deklariert zun&auml;chst das Ereignis, das durch den Timer ausgel&ouml;st wird:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Event TimerEvent()\r\n<span style=\"color:blue;\">Private <\/span>L_INTERVAL<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>L_ID<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n<span style=\"color:blue;\">Friend Sub <\/span>ErrRaise(E<span style=\"color:blue;\"> As Long<\/span>)\r\n    <span style=\"color:blue;\">Dim <\/span>sText<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>sSource<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">If <\/span>E &gt; 1000<span style=\"color:blue;\"> Then<\/span>\r\n        sSource = \"Application\" & \".WindowProc\"\r\n        Select Case E\r\n            <span style=\"color:blue;\">Case <\/span>eTooManyTimers\r\n                sText = \"No more than 1000 timers allowed per class\"\r\n            <span style=\"color:blue;\">Case <\/span>eCantCreateTimer\r\n                sText = \"Can''t create system timer\"\r\n        <span style=\"color:blue;\">End Select<\/span>\r\n        Err.Raise E Or vbObjectError, sSource, sText\r\n    <span style=\"color:blue;\">Else<\/span>\r\n        Err.Raise E, sSource\r\n    End If        \r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Property Get <\/span>Interval()<span style=\"color:blue;\"> As Long<\/span>\r\n    Interval = L_INTERVAL\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Property Let <\/span>Interval(lValue<span style=\"color:blue;\"> As Long<\/span>)\r\n    <span style=\"color:blue;\">Dim <\/span>b<span style=\"color:blue;\"> As Boolean<\/span>        \r\n    <span style=\"color:blue;\">If <\/span>lValue &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        <span style=\"color:blue;\">If <\/span>L_INTERVAL = lValue<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Property<\/span>\r\n        <span style=\"color:blue;\">If <\/span>L_INTERVAL<span style=\"color:blue;\"> Then<\/span>\r\n            b = TimerDestroy(Me)\r\n            <span style=\"color:blue;\">Debug.Assert<\/span> b\r\n        <span style=\"color:blue;\">End If<\/span>\r\n        L_INTERVAL = lValue\r\n        <span style=\"color:blue;\">If <\/span>TimerCreate(Me) = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n            ErrRaise eCantCreateTimer\r\n        <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">Else<\/span>\r\n        <span style=\"color:blue;\">If <\/span>(L_INTERVAL &gt; 0)<span style=\"color:blue;\"> Then<\/span>\r\n            L_INTERVAL = 0\r\n            b = TimerDestroy(Me)\r\n            <span style=\"color:blue;\">Debug.Assert<\/span> b\r\n        <span style=\"color:blue;\">End If<\/span>\r\n    End If        \r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Public Sub <\/span>RaiseInterval()\r\n    RaiseEvent TimerEvent\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Friend Property Get <\/span>TimerID()<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n    TimerID = L_ID\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Friend Property Let <\/span>TimerID(ID<span style=\"color:blue;\"> As Long<\/span>Ptr)\r\n    L_ID = ID\r\n<span style=\"color:blue;\">End Property<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Class_Terminate()\r\n    Interval = 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Klassenmodul CLS_AMV_Timer<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Event TimerEvent()<\/pre>\n<p>Die Variablen <b>L_INTERVAL <\/b>und <b>L_ID <\/b>speichern das Intervall eines Timers und die ID:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>L_INTERVAL<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>L_ID<span style=\"color:blue;\"> As Long<\/span>Ptr<\/pre>\n<p>Die Prozedur <b>ErrRaise <\/b>wird beim Auftreten eines Fehlers aufgerufen.<\/p>\n<p>&Uuml;ber die <b>Property Get<\/b>-Prozedur Interval k&ouml;nnen wir das Intervall eines Timers abrufen, mit der entsprechenden <b>Property Let<\/b>-Prozedur setzen wir das Intervall.<\/p>\n<p>Dabei &uuml;bergeben wir die Anzahl der Millisekunden, nach denen der Timer ausgel&ouml;st werden soll. Die Prozedur pr&uuml;ft, ob das Intervall gr&ouml;&szlig;er als <b>0 <\/b>ist, und stellt dieses ein. Wenn das zugewiesene Intervall gleich dem zuvor eingestellten Intervall ist, wird die Prozedur verlassen. Anderenfalls rufen wir die Prozedur <b>TimerDestroy <\/b>auf, die im Standardmodul <b>MDL_AMV_Timer <\/b>enthalten ist (siehe weiter unten).<\/p>\n<p>Die Methode <b>RaiseInterval <\/b>l&ouml;st das Ereignis <b>TimerEvent <\/b>aus, das wir im implementierenden Klassenmodul definieren. Schlie&szlig;lich gibt es noch zwei <b>Property<\/b>-Prozeduren, mit denen die <b>TimerID <\/b>gelesen und geschrieben werden kann, und die Methode <b>Class_Terminate<\/b>, welche das Intervall auf <b>0 <\/b>Millisekunden einstellt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Class_Terminate()\r\n    Interval = 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit kommen wir zum zweiten Modul, das f&uuml;r die Verwendung der Klasse wichtig ist.<\/p>\n<h2>Modul MOD_AMV_TIMER: Verwaltung der Timer<\/h2>\n<p>Das Modul <b>MOD_AMV_TIMER <\/b>enth&auml;lt alle Funktionen, um die Windows-Timer zu starten und zu stoppen. Es sorgt daf&uuml;r, dass bis zu 100 Timer gleichzeitig verwaltet werden k&ouml;nnen. Diese enth&auml;lt zun&auml;chst einige Deklarationen (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Enum eTimerError\r\n    eBaseTimer = 10100\r\n    eTooManyTimers = 10101\r\n    eCantCreateTimer = 10102\r\nEnd Enum\r\n#If Win64 Then\r\n    <span style=\"color:blue;\">Public <\/span>Declare PtrSafe Function SetTimer Lib \"user32\" (ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>Ptr, ByVal nIDEvent<span style=\"color:blue;\"> As Long<\/span>Ptr, _\r\n        ByVal uElapse<span style=\"color:blue;\"> As Long<\/span>, ByVal lpTimerFunc<span style=\"color:blue;\"> As Long<\/span>Ptr)<span style=\"color:blue;\"> As Long<\/span>Ptr\r\n    <span style=\"color:blue;\">Public <\/span>Declare PtrSafe Function KillTimer Lib \"user32\" (ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>Ptr, ByVal nIDEvent<span style=\"color:blue;\"> As Long<\/span>Ptr)<span style=\"color:blue;\"> As Long<\/span>\r\n#Else\r\n    <span style=\"color:blue;\">Public <\/span>Declare Function SetTimer Lib \"user32\" (ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>, ByVal nIDEvent<span style=\"color:blue;\"> As Long<\/span>, _\r\n        ByVal uElapse<span style=\"color:blue;\"> As Long<\/span>, ByVal lpTimerFunc<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n    <span style=\"color:blue;\">Public <\/span>Declare Function KillTimer Lib \"user32\" (ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>, ByVal nIDEvent<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n#End If\r\n<span style=\"color:blue;\">Private <\/span>Const cTimerMax<span style=\"color:blue;\"> As Long<\/span> = 100\r\n<span style=\"color:blue;\">Private <\/span>aTimers(1 To cTimerMax)<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>cTimerCount<span style=\"color:blue;\"> As Integer<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Deklarationen im Modul MDL_AMV_Timer<\/span><\/b><\/p>\n<p>Diese Deklarationen stellen sicher, dass wir die Windows-Timer-API sowohl in 32-Bit- als auch in 64-Bit-Umgebungen verwenden k&ouml;nnen. Das Enum <b>eTimerError <\/b>definiert eigene Fehlercodes f&uuml;r die Klasse.<\/p>\n<p><b>cTimerMax <\/b>legt die maximale Anzahl gleichzeitig laufender Timer fest. Das Array <b>aTimers <\/b>speichert Referenzen auf alle <b>Timer<\/b>-Objekte. <b>cTimerCount <\/b>gibt an, wie viele Timer aktuell verwendet werden.<\/p>\n<h2>Timer erstellen<\/h2>\n<p>In der Funktion <b>TimerCreate <\/b>wird der Windows-Timer &uuml;ber die API-Funktion <b>SetTimer <\/b>erstellt (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>TimerCreate(Timer<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER)<span style=\"color:blue;\"> As Boolean<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n    On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n    Timer.TimerID = SetTimer(CLngPtr(0), CLngPtr(0), Timer.Interval, AddressOf TimerProc)\r\n    <span style=\"color:blue;\">If <\/span>Timer.TimerID<span style=\"color:blue;\"> Then<\/span>\r\n        TimerCreate = <span style=\"color:blue;\">True<\/span>\r\n        For i = 1 To cTimerMax\r\n            <span style=\"color:blue;\">If <\/span>aTimers(i) Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n                <span style=\"color:blue;\">Set<\/span> aTimers(i) = Timer\r\n                <span style=\"color:blue;\">If <\/span>i &gt; cTimerCount<span style=\"color:blue;\"> Then<\/span> cTimerCount = i\r\n                <span style=\"color:blue;\">Exit Function<\/span>\r\n            <span style=\"color:blue;\">End If<\/span>\r\n        <span style=\"color:blue;\">Next<\/span>\r\n        Timer.ErrRaise eTooManyTimers\r\n    <span style=\"color:blue;\">Else<\/span>\r\n        Timer.TimerID = 0\r\n        Timer.Interval = 0\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Die Funktion TimerCreate<\/span><\/b><\/p>\n<p>Anschlie&szlig;end suchen wir einen freien Platz im Array <b>aTimers<\/b>. Bei Erfolg speichern wir das Objekt, andernfalls wird ein Fehler geworfen.<\/p>\n<h2>Timer zerst&ouml;ren<\/h2>\n<p>Diese Funktion <b>TimerDestroy <\/b>sucht im Array den passenden Timer anhand der ID, beendet ihn mit <b>KillTimer <\/b>und entfernt die Referenz (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>TimerDestroy(Timer<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER)<span style=\"color:blue;\"> As Long<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>, f<span style=\"color:blue;\"> As Boolean<\/span>\r\n    On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n    For i = 1 To cTimerCount\r\n        <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> aTimers(i) Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n            <span style=\"color:blue;\">If <\/span>Timer.TimerID = aTimers(i).TimerID<span style=\"color:blue;\"> Then<\/span>\r\n                f = KillTimer(CLngPtr(0), Timer.TimerID)\r\n                <span style=\"color:blue;\">Set<\/span> aTimers(i) = Nothing\r\n                TimerDestroy = <span style=\"color:blue;\">True<\/span>\r\n                <span style=\"color:blue;\">Exit Function<\/span>\r\n            <span style=\"color:blue;\">End If<\/span>\r\n        <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">Next<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Die Funktion TimerDestroy<\/span><\/b><\/p>\n<h2>Die Prozedur TimerProc<\/h2>\n<p>Windows ruft diese Prozedur auf, wenn ein Timer abgelaufen ist. Die Prozedur sucht den passenden Timer und ruft dessen Methode <b>RaiseInterval <\/b>auf, damit die Klasse das Event ausl&ouml;sen kann (siehe Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TimerProc(ByVal hWnd<span style=\"color:blue;\"> As Long<\/span>Ptr, ByVal uMsg<span style=\"color:blue;\"> As Long<\/span>, ByVal nIDEvent<span style=\"color:blue;\"> As Long<\/span>Ptr, ByVal dwTime<span style=\"color:blue;\"> As Long<\/span>)\r\n    <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n    On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n    For i = 1 To cTimerCount\r\n        <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> (aTimers(i) Is Nothing)<span style=\"color:blue;\"> Then<\/span>\r\n            <span style=\"color:blue;\">If <\/span>nIDEvent = aTimers(i).TimerID<span style=\"color:blue;\"> Then<\/span>\r\n                aTimers(i).RaiseInterval\r\n                <span style=\"color:blue;\">Exit Sub<\/span>\r\n            <span style=\"color:blue;\">End If<\/span>\r\n        <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">Next<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Die Funktion TimerProc<\/span><\/b><\/p>\n<h2>Beispiel: Das Formular FRM_CLASS_TIMER<\/h2>\n<p>Wenn wir auf einen Timer reagieren wollen, indem wir f&uuml;r diesen eine Ereignisprozedur implementieren, ben&ouml;tigen wir zwingend ein Klassenmodul. Wir haben uns zur Vereinfachung entschieden, dazu das Klassenmodul eines Formulars zu nutzen.<\/p>\n<p>In diesem Klassenmodul haben wir den Code aus Listing 6 hinterlegt. Hier werden zun&auml;chst drei Objekte der Klasse <b>CLS_AMV_TIMER <\/b>mit <b>WithEvents <\/b>deklariert. Dadurch k&ouml;nnen wir auf das Ereignis <b>TimerEvent <\/b>reagieren:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER01<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER02<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER03<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER01_TimerEvent()\r\n    Me.LB01.Caption = Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER02_TimerEvent()\r\n    Me.LB02.Caption = Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER03_TimerEvent()\r\n    Me.LB03.Caption = Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n    \r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER01 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER02 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER03 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    \r\n    C_TIMER01.Interval = 1000\r\n    C_TIMER02.Interval = 1000\r\n    C_TIMER03.Interval = 1000\r\n    \r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n    C_TIMER01.Interval = 0\r\n    C_TIMER02.Interval = 0\r\n    C_TIMER03.Interval = 0\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER01 = Nothing\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER02 = Nothing\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER03 = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Klassenmodul des Formulars FRM_CLASS_TIMER<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER01<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER02<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER03<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER<\/pre>\n<p>Im <b>Form_Load <\/b>werden die Timer gestartet. Dazu erstellen wir mit New <b>CLS_AMV_TIMER <\/b>jeweils eine neue Instanz der Klasse <b>CLS_AMV_Timer <\/b>und weisen diese den Variablen <b>C_TIMER01<\/b>, <b>C_TIMER02 <\/b>und <b>C_TIMER03 <\/b>zu.<\/p>\n<p>Dann stellen wir die Eigenschaft <b>Interval<\/b> jeweils auf 1.000 Millisekunden ein, damit die Timer einmal pro Sekunde ausgel&ouml;st werden.<\/p>\n<p>Nun m&uuml;ssen wir noch die Ereignisse implementieren, in denen wir den Code unterbringen, der beim Ausl&ouml;sen des Timers ausgef&uuml;hrt werden soll.<\/p>\n<p>Dazu w&auml;hlen wir im linken Kombinationsfeld im Codefenster den Eintrag f&uuml;r den jeweiligen Timer aus, zum Beispiel <b>C_TIMER01<\/b>.<\/p>\n<p>Im rechten Kombinationsfeld wird jetzt automatisch das einzige Ereignis der <b>Timer<\/b>-Klasse ausgew&auml;hlt und es erscheint die entsprechende Ereignisprozedur im Codefenster (siehe Bild 2). Diese f&uuml;llen wir mit dem gew&uuml;nschten Code, zum Beispiel:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_498_002.png\" alt=\"Implementieren des TimerEvent-Ereignisses f&uuml;r einen Timer\" width=\"599,559\" height=\"300,5963\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Implementieren des TimerEvent-Ereignisses f&uuml;r einen Timer<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>C_TIMER01_TimerEvent()\r\n    Me.LB01.Caption = Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier soll das Bezeichnungsfeld mit dem Namen <b>LB01 <\/b>mit dem aktuellen Datum und der Uhrzeit in einem bestimmten Format gef&uuml;llt werden. Im <b>Unload<\/b>-Ereignis werden die Timer schlie&szlig;lich gestoppt. Dazu stellen wir ihre Eigenschaft <b>Interval <\/b>auf <b>0 <\/b>ein und leeren die Objektvariablen. So bleibt kein Timer aktiv und der Speicher wird bereinigt. Das Ergebnis sehen wir in Bild 3.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_498_001.png\" alt=\"Das Formular mit drei Timern in Aktion\" width=\"424,5589\" height=\"258,4272\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Das Formular mit drei Timern in Aktion<\/span><\/b><\/p>\n<h2>Timer ohne Formular<\/h2>\n<p>Wie im Titel dieses Artikels angek&uuml;ndigt, wollen wir aber auch Timer vollkommen unabh&auml;ngig von einem Formular starten k&ouml;nnen. Das bedeutet lediglich, dass wir den Code, der das <b>TimerEvent<\/b>-Ereignis implementiert, in einem Klassenmodul implementieren m&uuml;ssen.<\/p>\n<p>Also kopieren wir den Inhalt aus dem Klassenmodul des Formulars in ein neues Klassenmodul namens <b>clsTimerBeispiel<\/b>. Hier k&ouml;nnen wir die Deklarationen und die Implementierungen des Ereignisses <b>TimerEvent <\/b>f&uuml;r die drei Timer weitgehend beibehalten (siehe Listing 7).<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER01<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER02<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private <\/span>WithEvents C_TIMER03<span style=\"color:blue;\"> As <\/span>CLS_AMV_TIMER\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER01_TimerEvent()\r\n    <span style=\"color:blue;\">Debug.Print<\/span> \"Timer 1: \" & Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER02_TimerEvent()\r\n    <span style=\"color:blue;\">Debug.Print<\/span> \"Timer 2: \" & Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>C_TIMER03_TimerEvent()\r\n    <span style=\"color:blue;\">Debug.Print<\/span> \"Timer 1: \" & Format(Now, \"dd mm yyyy hh:nn:ss\")\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Public Sub <\/span>TimerStarten()\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER01 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER02 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER03 = <span style=\"color:blue;\">New<\/span> CLS_AMV_TIMER\r\n    \r\n    C_TIMER01.Interval = 1000\r\n    C_TIMER02.Interval = 1000\r\n    C_TIMER03.Interval = 1000    \r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Public Sub <\/span>TimerStoppen()\r\n    C_TIMER01.Interval = 0\r\n    C_TIMER02.Interval = 0\r\n    C_TIMER03.Interval = 0\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER01 = Nothing\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER02 = Nothing\r\n    <span style=\"color:blue;\">Set<\/span> C_TIMER03 = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Klassenmodul mit Timern<\/span><\/b><\/p>\n<p>Allerdings geben wir die Uhrzeit in Implementierungen von <b>TimerEvent<\/b> nicht in Bezeichnungsfeldern aus, sondern im Direktbereich des VBA-Editors.<\/p>\n<p>Statt der Ereignisprozeduren, die durch die Formularereignisse <b>Beim Laden <\/b>und <b>Beim Entladen <\/b>ausgel&ouml;st werden, verwenden wir zwei &ouml;ffentliche Prozeduren namens <b>TimerStarten <\/b>und <b>TimerStoppen<\/b>.<\/p>\n<p>Diese enthalten jedoch die gleichen Anweisungen wie die entsprechenden Ereignisprozeduren des Formulars. In einem neuen Standardmodul f&uuml;gen wir nun den Code ein, mit dem wir die Klasse <b>clsTimerBeispiele<\/b> deklarieren und initialisieren. Die Deklaration lautet wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>objTimerBeispiel<span style=\"color:blue;\"> As <\/span>clsTimerBeispiel<\/pre>\n<p>Um die Timer zu initialisieren und zu starten, verwenden wir die folgende Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TimerStarten()\r\n    <span style=\"color:blue;\">Set<\/span> objTimerBeispiel = <span style=\"color:blue;\">New<\/span> clsTimerBeispiel\r\n    objTimerBeispiel.TimerStarten\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Schlie&szlig;lich k&ouml;nnen wir die Timer mit dieser Prozedur wieder stoppen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TimerStoppen()\r\n    objTimerBeispiel.TimerStoppen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit dieser L&ouml;sung kannst Du mehrere unabh&auml;ngige Timer gleichzeitig steuern. Die Timer k&ouml;nnen sowohl innerhalb des Klassenformulars eines Formulars als auch in alleinstehenden Klassenmodulen implementiert werden.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>AMV_CLASS_TIMER.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/016ADEBC-28B3-4535-B757-C712AD972EFA\/vbe_498.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unter Access kennt man eigentlich nur den Timer, den das Formular-Objekt mitbringt. Damit k&ouml;nnen wir ein Ereignis definieren, das in einem bestimmten Zeitintervall ausgel&ouml;st wird. Was aber, wenn wir einen Timer einmal au&szlig;erhalb des Kontexts eines Formulars ben&ouml;tigen? Dann erstellen wir uns einfach eine eigene Timer-Klasse. Dazu sind zwar ein paar Tricks und API-Funktionen n&ouml;tig, aber das soll kein Hindernis sein. Deshalb zeigen wir in diesem Beitrag im Detail, wie das gelingt und wie sich dieser Timer in der Praxis einsetzen l&auml;sst. Und im Gegensatz zum Formulartimer haben wir noch einen Vorteil: Wir k&ouml;nnen n&auml;mlich nicht nur einen, sondern beliebig viele Timer einsetzen und laufen lassen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012026,662026,44000026,44000025,44000033],"tags":[],"yst_prominent_words":[],"class_list":["post-55000498","post","type-post","status-publish","format-standard","hentry","category-66012026","category-662026","category-Outlook_programmieren","category-VBAProgrammierung","category-Visual_Basic_Programmierung"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000498"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000498\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000498"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}