Ereignisse

Aus VBA-wiki
Version vom 28. Januar 2023, 00:34 Uhr von Pwania (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Anwender und Anwendung

Eigentlich ist es wie im echten Leben: Wir werden bestimmt von Geschehnissen und Entscheidungen.

Bei der Programmierung ist es nicht anders, nur dass hier zwischen Anwender-Ereignissen und Anwendungs-Ereignissen unterschieden wird.

Die Anwender-Ereignisse sind bei dieser Analogie als Entscheidungen zu sehen, das bedeutet, der Anwender hat einen Text eingegeben, einen Knopf gedrückt oder eine Frage bestätigt, wodurch in der Programmierung nun weitere Schritte durchgeführt werden.

Die Anwendungs-Ereignisse sind hingegen analog zu Geschehnissen zu betrachten, welche aus Sicht der Programmierung willkürlich (eine neue Datei wird angelegt) oder geplant (nach Ablauf einer vorgegebenen Zeit) eintreten können.

Ereignisse bestimmen also die Arbeitsabläufe letztendlich sämtlicher Programme. Unser Rechner ist nichts weiter als eine übertrieben komplizierte elektrische Wärmequelle, wenn nicht zu bestimmten Ereignissen oder als Reaktion auf eine Benutzereingabe immer mal wieder eine Aufgabe erfüllt werden könnte ...

Auto-Makros

Auto-Makros werden beim Starten bzw. beim Beenden der Anwendung und / oder beim Öffnen bzw. beim Schließen der Datei, welche das Auto-Makro enthält, ausgeführt. Sie stehen in den drei Anwendungen Word, Excel und PowerPoint zur Verfügung, unterscheiden sich jedoch teilweise in Schreibweise und Einsatzgebiet.

Word

Name Beschreibung Anwendungsbereich
AutoNew Wird ausgeführt, wenn
  • von dieser Vorlage ein neues Dokument erzeugt wird
Vorlagen
AutoOpen Wird ausgeführt, wenn
  • dieses Dokument
  • diese Vorlage geöffnet wird
Vorlagen
Dokumente
AutoClose Wird ausgeführt, wenn
  • dieses Dokument
  • diese Vorlage geschlossen wird
Vorlagen
Dokumente
AutoExec Wird ausgeführt, wenn
  • Word gestartet bzw.
  • das Add-In geladen wird
Ausschließlich Add-Ins und Normal.dot(m)
AutoExit Wird ausgeführt, wenn
  • Word beendet bzw.
  • das Add-In entladen wird
Ausschließlich Add-Ins und Normal.dot(m)

Excel

Name Beschreibung Anwendungsbereich
Auto_Open Wird ausgeführt, wenn
  • diese Arbeitsmappe / diese Vorlage geöffnet wird
  • dieses Add-In geladen bzw. Excel gestartet wird
Vorlagen
Arbeitsmappen
Add-Ins
Auto_Close Wird ausgeführt, wenn
  • diese Arbeitsmappe / diese Vorlage geschlossen wird
  • dieses Add-In entladen bzw. Excel beendet wird
Vorlagen
Arbeitsmappen
Add-Ins

PowerPoint

In PowerPoint stehen die Auto-Makros ausschließlich in Add-Ins zur Verfügung. Wenn Sie auch in einer Präsentation einen Weg benötigen, um beim Starten / Laden etwas auszuführen (um zum Beispiel auf Ereignisse zuzugreifen), können Sie (ab PowerPoint 2007) alternativ ein (leeres) Ribbon erzeugen und dessen 'onLoad'-Callback einsetzen.

Name Beschreibung Anwendungsbereich
Auto_Open Wird ausgeführt, wenn
  • dieses Add-In geladen wird (beim Starten von PowerPoint)
Ausschließlich in Add-Ins
Auto_Close Wird ausgeführt, wenn
  • dieses Add-In entladen wird (wenn PowerPoint beendet wird)
Ausschließlich in Add-Ins

Benutzeroberflächen-Ereignisse

Dialog-Ereignisse

Siehe Eigene Dialoge (Userforms)

Ereignisse des Menübandes

Siehe Menüband (Ribbon)

Dokument- (Präsentations- bzw. Arbeitsmappen-) Ereignisse

Anwendungsereignisse

Die Anwendungsereignisse werden von der entsprechenden Office-Anwendung zur Verfügung gestellt und können wie hier beschrieben mithilfe einer Ereignisklasse abgerufen werden.

Sie umfassen typischerweise Ereignisse wie das Öffnen, Drucken, Speichern von Dateien und reagieren auf Benutzerinteraktion wie das Ändern der Auswahl, das Wechseln zu einer anderen offenen Datei etc.

Ereignisklasse

1. Deklarieren Sie eine Objektvariable, welche die Anwendung entgegennehmen soll, deren Ereignisse Sie empfangen möchten. Beachten Sie dabei das Schlüsselwort WithEvents:

Private WithEvents myEvents As Application

2. Initialisieren Sie diese Variable bei der Initialisierung der Klasse.

Private Sub Class_Initialize()
   
   Set myEvents = Application
End Sub

3. Nun stehen Ihnen die Anwendungs-Ereignisse zur Verfügung:

  • Setzen Sie die Auswahl 'Objekt' auf 'myEvents'
  • Wählen Sie in der Liste 'Prozedur' das gewünschte Ereignis

Bitte beachten: Verwenden Sie immer die Prozedur-Liste, um ein neues Ereignis hinzuzufügen, weil viele Ereignisse Übergabeparameter verwenden.

Ereignisprozedur in einem eigenen Modul

1. Erstellen Sie ein Modul, welches die Ereignisklasse ansprechen soll.

2. Deklarieren Sie eine Objektvariable, welche die Ereignisklasse entgegennimmt. Da der Zugriff auf die Ereignisse permanent sein soll, verwenden Sie eine Modulvariable:

Private myEvents As clsEvents

3. Erstellen Sie eine Prozedur, welche die Ereignisklasse instanziiert. Hierfür eignet sich das passende Auto-Makro, welches beim Starten bzw. Öffnen ausgeführt wird.

Public Sub Auto_Open()
   
   Set myEvents = New clsEventsExcel
End Sub

Wichtige Hinweise

  • Die Ereignisse können erst von Ihnen abgefangen werden, wenn die Klasse instanziiert wurde. Führen Sie dazu das Automakro aus, das Sie zu diesem Zweck erstellt haben.
  • Die Verbindung zu den Ereignissen kann in der Entwicklungsphase verloren gehen, wenn beim Testen Fehler auftreten oder wenn Sie größere Teile der Programmierung bearbeiten. Sie können bei Bedarf durch das Ausführen des Automakros diese wieder aktivieren.

Eigene Ereignisse

Wenn Sie eine auf mehrere Projekte verteilte Lösung entwickeln, können Sie eigene Ereignisse auslösen und entsprechend darauf reagieren. Sie können eigene Ereignisse zwar auch innerhalb eines einzelnen Projektes verwenden, hier würde der Nutzen jedoch nicht den Aufwand rechtfertigen, weil nach der Abarbeitung eines Schrittes der nächste Schritt direkt aufgerufen werden kann.

Szenario

Sie verwenden in Ihren Lösungen eine gemeinsame ToolBox, welche all jene Hilfefunktionen enthält, die für alle Lösungen relevant sind. Für die Kundenanpassungen verwenden Sie ein eigenes Add-In, welches die kundenspezifische Funktionalitäten enthält. Das Kundenmodul hat eine Referenz auf die ToolBox, damit Sie auf dessen Hilfsfunktionen zugreifen können.

Eine Aufgabe Ihrer Lösung besteht darin, eine neue Datei zu erstellen. Die Aufgabe wird größtenteils von der ToolBox erfüllt, aber im Anschluss möchten Sie die Möglichkeit haben, zusätzliche kundenspezifische Schritte auszuführen. Nach der Erstellung der Datei und den generellen Schritten soll also die ToolBox dem Kundenmodul mitteilen, dass eine neue Datei erstellt und von der ToolBox vorbereitet worden ist.

Ereignis-Server

Der Ereignis-Server ist das Projekt, welches Ereignisse auslösen können soll, in unserem Szenario die ToolBox.

Eigene Ereignisklasse

  • Erstellen Sie ein Klassenmodul, zum Beispiel 'clsEventServer'.
  • Stellen Sie die Eigenschaft 'Instancing' auf den Wert '2 - PublicNotCreatable'.
  • Erstellen Sie die gewünschten Ereignisse:
Public Event AfterCreateFile()
Public Event BeforeLoadData(ByVal strDataFile As String, ByRef blnCancel As Boolean)
  • wobei
    • 'AfterCreateFile' aufgerufen werden soll, nachdem die generellen Vorbereitungen einer neuen Datei abgeschlossen worden sind.
    • 'BeforeLoadData' aufgerufen werden soll, bevor neue Daten in die offene Datei eingelesen werden.
      • Der Name der Datendatei soll beim Ereignis mit übergeben werden.
      • Das Laden der Daten soll bei Bedarf abgebrochen werden können, indem der Parameter 'blnCancel' auf 'False' gesetzt wird.
  • Erstellen Sie die entsprechenden Ereignis-Aufrufe:
Public Sub RaiseEventAfterCreateFile()
    
    RaiseEvent AfterCreateFile
End Sub
Public Sub RaiseEventBeforeLoadData(ByVal strDataFile As String, ByRef blnCancel As Boolean)
    
    RaiseEvent BeforeLoadData(strDataFile, blnCancel)
End Sub

Bereitstellung des Ereignis-Servers

Um den Ereignisse der Ereignisklasse auslösen zu können, muss ein permanenter Zugriff auf eine Modulvariable über eine Funktion bereitgestellt werden. Die Modulvariable sorgt dafür, dass immer auf die gleiche Instanz der Ereignisklasse zugegriffen wird, die Funktion stellt sicher, dass diese Instanz bereitgestellt wird:

  • Erstellen Sie ein Modul, zum Beispiel 'modEventsToolBox'.
  • Fügen Sie wie hier gezeigt eine private Modulvariable und eine öffentliche Funktion hinzu:
Private myEventServer As clsEventServer


Public Function EventServer() As clsEventServer

    If myEventServer Is Nothing Then Set myEventServer = New clsEventServer
    Set EventServer = myEventServer
End Function

Auslösen eines Ereignisses

Innerhalb des Projektes, das die Ereignisse zur Verfügung stellt, können nun die Ereignisse wie folgt ausgelöst werden:

  • Einfacher Aufruf eines Ereignisses ohne Parameter:
   EventServer.RaiseEventAfterCreateFile          
  • Aufruf eines Ereignisses mit Berücksichtigung des Abbruchs:
   Dim strDataFile As String
   Dim blnCancel As Boolean
   
   blnCancel = False
   EventServer.RaiseEventBeforeLoadData strDataFile, blnCancel
   If blnCancel = True Then
       ' Weitere Schritte abbrechen
   End If

Ereignis-Client

Der Ereignis-Client ist das Projekt, welches auf Ereignisse reagieren können soll, in unserem Szenario das Kundenmodul. Das Projekt benötigt eine Referenz auf das Projekt des Ereignis-Servers (in unserem Szenario die ToolBox).

Ereignis-Klasse

Analog zu Anwendungs-Ereignissen benötigt der Ereignis-Client eine Ereignis-Klasse:

  • Fügen Sie dem Kundenprojekt eine neue Klasse hinzu, zum Beispiel 'clsEventClient'.
  • Der Zugriff auf den Ereignis-Server erfolgt über eine private Klassenvariable:
Private WithEvents myEvents As ToolBox.clsEventServer     ' 'ToolBox' is der Name des Projektes des Ereignis-Servers
  • Bitte beachten: Die Ereignisklasse 'clsEventServer' wird nur dann bereitgestellt, wenn deren Eigenschaft 'Instancing' den Wert '2 - PublicNotCreatable' hat!
  • Das Ereignis 'Class_Initialize' der Ereignis-Klasse setzt die Klassenvariable auf die Instanz, welche der Ereignis-Server mit seiner Funktion 'EventServer' bereitstellt:
Private Sub Class_Initialize()
    
    Set myEvents = ToolBox.EventServer
End Sub
  • Die Ereignisse selbst können nun über die Auswahlfelder 'Objekt' und 'Prozedur' abgerufen werden:
Private Sub myEvents_AfterCreateFile()

End Sub
Private Sub myEvents_BeforeLoadData(ByVal strDataFile As String, blnCancel As Boolean)

End Sub

Instanziierung der Ereignis-Klasse

Ebenfalls analog zu den Anwendungs-Ereignissen wird anschließend in einem Modul eine permanente Instanz der Ereignisklasse erstellt:

Private myEvents As clsEventClient
Public Sub Auto_Open()          ' bzw. AutoOpen / AutoExec
    
    Set myEvents = New clsEventClient
End Sub

Andere Ereignisse zulassen mit 'DoEvents'

Das Ausführen von Makros ist aus Sicht der Office-Anwendung (Word, Excel, PowerPoint etc.) ein exklusiver Vorgang: Andere Vorgänge können in dieser Zeit weder in der Anwendung noch in VBA ausgeführt werden. Das bedeutet, dass längere Vorgänge über längere Zeit die Anwendung komplett für sich beanspruchen und keine anderen Schritte zulassen können.

Wenn Sie ganz bewusst diese Exklusivität unterbrechen möchten, um zum Beispiel auf eine Eingabe der Tastatur zu reagieren, verwenden Sie den Befehl 'DoEvents'. Dieser sorgt dafür, dass alle anstehenden Ereignisse der Office-Anwendung bzw. von VBA ausgeführt werden, bevor der unterbrochene Programmlauf wieder fortgesetzt wird.

Konkretes Szenario

Sie haben eine Schleife geschrieben, mit der tausende von Daten in einer Excel-Tabelle ausgewertet werden. Sie möchten gerne dafür sorgen, dass der Anwender diesen Vorgang mit der 'ESC'-Taste abbrechen kann. Da die Schleife keinen Raum für weitere Ereignisse bietet, wird das Drücken der 'ESC'-Taste erst dann von Excel entgegengenommen, wenn der aktuelle Programmlauf komplett abgeschlossen wurde.

Abhilfe schafft hier ein Aufruf des 'DoEvents'-Befehls. Wenn der Programmlauf diesen Befehl antrifft, werden alle anstehenden Ereignisse abgearbeitet, bevor er weiter fortgesetzt wird, somit auch das Drücken der 'ESC'-Taste.

Bitte beachten: Dieses Beispiel setzt voraus, dass zum Beispiel ein (ungebundener) Dialog auf das Drücken der 'ESC'-Taste reagieren kann, um dann wiederum die weitere Ausführung der Schleife abzubrechen.

Wichtig: 'DoEvents' hat keiner Einfluss auf andere Programme oder das Verhalten Ihres Betriebssystems. VBA, Makros und somit 'DoEvents' betreffen ausschließlich die Office-Anwendung, in der sie ausgeführt werden.