Ereignisse in der Office-Programmierung

Veröffentlicht: 13. Nov 2000 | Aktualisiert: 14. Jun 2004
Von Peter Monadjemi

Auf dieser Seite

 Die Rolle der Ereignisse
 Die Ereignistypen
 Das Application-Objekt
 Der Event-Handler
 Rückmeldungen an die Anwendung
 Ein abschließendes Beispiel
 Ausblick

Diesen Artikel können Sie hier lesen dank freundlicher Unterstützung der Zeitschrift:

Bild05

Office 2000 wartet mit einer Reihe neuer Ereignisse auf, mit deren Hilfe Sie flexibleren Programmcode schreiben können. Insbesondere Ereignisse auf Anwendungsebene erlauben die Steuerung von Office-Anwendungen per Prozedur. Ereignisse spielen in der normalen VBA-Programmierung meistens keine Rolle. Eine Prozedur wird aufgerufen, führt eine Reihe von VBA-Befehlen aus und wird wieder beendet. Anders sieht es aus, wenn eine Prozedur auf bestimmte Aktionen des Benutzers reagieren oder sich in den Start einer Office-Anwendung einklinken soll. In diesem Fall ist die Prozedur auf Ereignisse angewiesen, dem offiziellen Mitteilungsdienst jeder Anwendung, die auf einer grafischen Oberfläche basiert. In diesem Beitrag geht es um die Rolle der Ereignisse in der Office-Programmierung und vor allem um die Verbesserungen in Office 2000.
Bei der VBA-Programmierung gibt es auf den ersten Blick nicht viel Neues zu entdecken. Eine Neuerung, die erst auf den zweiten Blick sichtbar wird, betrifft die Ereignisse. Wenngleich sich an dem Prinzip der ereignisorientierten Abarbeitung von Office-VBA-Programmen nichts geändert hat, gibt es im Vergleich zu Office 97 eine wichtige Verbesserung. Das Application-Objekt von Excel und Word verfügt über mehr Ereignisse als sein Vorgänger, was eine sehr viel flexiblere Programmierung ermöglicht. Soll zum Beispiel in jedes Word-Dokument vor dem Speichern das Datum der letzten Änderung eingetragen oder die aktuelle Position der Textmarke gespeichert werden, müssen Sie in Office 2000 nur einen Event-Handler einrichten. Doch dazu kommen wir später.

Die Rolle der Ereignisse

Ereignisse besitzen in der VBA-Programmierung, anders als im täglichen Leben, eine eng umrissene Bedeutung. Sie sind dazu da, einer VBA-Prozedur bestimmte „Vorkommnisse" während ihrer Ausführung mitzuteilen. Die Vorkommnisse sind genau definiert und bei den Office-Anwendungen vom Typ der Anwendung abhängig. Word kennt unter anderem die Vorkommnisse Dokument wurde geöffnet und Dokument wird mit Dokumentvorlage neu angelegt, die etwa in Access oder Outlook keinen Sinn ergeben würden und die es daher auch nicht gibt.
Das Mitteilen eines Vorkommnisses wird durch den Aufruf einer so genannten Ereignisprozedur realisiert. Sie unterscheidet sich von einer normalen VBA-Prozedur dadurch, dass sie automatisch durch die Office-Anwendung aufgerufen wird. Konkret bedeutet das, dass immer wenn ein neues Dokument angelegt wird, der Dokumentvorlage (im allgemeinen Normal.dot) das Vorkommnis Neues Dokument wurde angelegt gemeldet wird. Das hat zur Folge, dass in der Dokumentvorlage, also zum Beispiel beim Document-Objekt der Normal.dot, das New-Ereignis ausgelöst und die Ereignisprozedur Document_New aufgerufen und ausgeführt wird. Enthält die Ereignisprozedur keine Befehle, was meistens der Fall ist, hat der Aufruf keine Folgen, aber er erfolgt trotzdem. Durch den Aufruf der Ereignisprozedur wird dem Programm mitgeteilt, dass ein bestimmtes Ereignis eingetreten ist.
Hinter der ereignisorientierten Programmausführung einer VBA-Prozedur steckt der Nachrichtenmechanismus von Windows, der an dieser Stelle nicht ausführlicher beschrieben werden soll. Er ist im Gegensatz zu Visual Basic für die VBA-Programmierung nicht relevant.
Ereignisse erscheinen angehenden VBA-Programmierern meist recht komplex, sind es aber gar nicht. Führen Sie zum Kennenlernen der Ereignisse folgende Schritte aus:

  • Starten Sie Word (ab Version 97), laden Sie die Dokumentvorlage Normal.dot und zeigen Sie den VBA-Editor an.

  • Wählen Sie im Projekt-Fenster den Eintrag ThisDocument aus (er sollte voreingestellt sein) und öffnen Sie das Codefenster.

  • Wählen Sie in der linken Auswahlliste (hier ist Allgemein voreingestellt) den Eintrag Document aus. In der rechten Auswahlliste erscheint der Eintrag New. Sie sehen jetzt die Ereignisprozedur Document_New, genauer ihren noch leeren Rahmen (Bild 1).

  • Tragen Sie in diesen Rahmen den folgenden Befehl ein:

    Msgbox "Holla, es ist jetzt: " & Time, _  
        vbInformation, ActiveDocument.Name
    
  • Schließen Sie den VBA-Editor, speichern Sie das Dokument und schließen Sie es.

  • Legen Sie in Word ein neues Dokument an. Die Meldung wird nun angezeigt.

Bild01


Das passiert jedes Mal, wenn Sie ein neues Dokument anlegen, das auf der Normal.dot basiert, da bei jedem Anlegen eines neuen Dokuments in der Dokumentvorlage (also nicht in dem neu angelegten Dokument) ein New-Ereignis ausgelöst und dadurch die Ereignisprozedur Document_New aufgerufen wird. Beachten Sie dabei, dass obwohl die Prozedur in der Normal.dot ausgeführt wird, über das ActiveDocument-Objekt ein Zugriff auf das aktuelle, also neu angelegte Dokument möglich ist.
Wenn Sie sich jetzt vorstellen, dass an Stelle der Uhrzeitausgabe bestimmte Einträge in dem neu angelegten Dokument vorgenommen werden oder der Aufruf mit Zeitpunkt und Name des Autors in einer Logdatei protokolliert wird, erhalten Sie ein Gefühl für die Möglichkeiten von Ereignissen. Der Vorteil von Ereignissen besteht darin, dass ein VBA-Programm sich nicht darum kümmern muss, einen bestimmten Zustand zu ermitteln (etwa Wurde das Programm schon geschlossen?). Statt dessen teilt der Mitteilungsdienst der Office-Anwendung dem Programm alle wichtigen Vorkommnisse durch Aufruf der dafür vorgesehenen Ereignisprozeduren mit.
Ereignisse sind relativ neu in der Office-Programmierung, sie wurden erst mit Office 97 eingeführt. Einen gewissen Automatismus gab es aber schon zuvor, und zwar die Auto-Makros. Dabei handelt es sich um Prozeduren (oder Module), die bestimmte Namen tragen, damit sie von der Anwendung automatisch zu bestimmten Anlässen ausgeführt werden. Ein Beispiel ist das AutoNew-Makro. Enthält eine Dokumentvorlage in einem allgemeinen Modul eine Prozedur mit dem Namen AutoNew, wird ihr Inhalt immer dann ausgeführt, wenn ein neues Dokument auf der Grundlage der Dokumentvorlage angelegt wird. Kommt Ihnen das bekannt vor? Genau dafür ist auch das New-Ereignis zuständig. Sehen sie Auto-Makros als ein Überbleibsel aus jener Ära an, in der es noch keine Ereignisse gab. (Enthält ein Dokument Auto-Makros und Ereignisprozeduren, werden beide ausgeführt.)

Die Ereignistypen

Haben Sie das Prinzip der Ereignisse verstanden und die ersten Beispiele ausprobiert, möchten Sie vielleicht auf sehr konkrete Ereignisse reagieren, zum Beispiel das Einfärben einer Textpassage. Zwei Gründe holen allzu experimentierfreudige VBA-Programmierer wieder auf den Boden der Realität zurück. Zum einen sind Ereignisse in den Office-Anwendungen relativ dünn gesät. Zum anderen existieren sie nicht global, sondern sind immer an ein Objekt gebunden. So unterstützt das Document-Objekt auch bei Word 2000 nur drei Ereignisse: New, Open und Close. Festzustellen, wann ein Anwender eine Formatierung benutzt oder eine Formatvorlage auswählt, ist also mit Ereignissen nicht möglich (bezeihungsweise nur indirekt über das WindowSelectionChange-Ereignis). Das ist auch gut so, denn jedes zusätzliche Ereignis erhöht den internen Verwaltungsaufwand der Office-Anwendung.
Um herauszubekommen, welche Ereignisse ein Objekt unterstützt, gehen Sie wie folgt vor:

  • Öffnen Sie den VBA-Editor, wählen Sie das Objekt im Projekt-Explorer und öffnen Sie das Codefenster.

  • Wählen Sie das Objekt in der Objektliste (linke Auswahlliste).

  • In der rechten Auswahlliste, der Ereignisliste, sehen Sie daraufhin alle Ereignisse. Die Ereignisse eines Objekts werden selbstverständlich auch im Objektkatalog angezeigt. Sie erkennen sie an dem Blitzsymbol (Bild 2). Wenn Sie Zeit haben, probieren Sie alle Ihre Office-Anwendungen durch. Sie erhalten schnell einen Überblick über die Rolle, die Ereignisse in den einzelnen Anwendungen spielen.

Bild02

Das Application-Objekt

Das im letzten Abschnitt beschriebene Verfahren zeigt Ihnen nur jene Objekte an, die im Projekt-Explorer aufgelistet werden. Neben diesen Objekten verfügt jede Anwendung bekanntlich über ein Application-Objekt, das bei Excel, Word und Outlook ebenfalls auf Ereignisse reagieren kann. Es stellt sich die Frage, wie sich die Ereignisse nutzen lassen, wenn sie im Codefenster gar nicht aufgelistet werden. Die Antwort lautet, dass sie selbstverständlich aufgelistet werden, allerdings ist dazu ein wenig Programmierung erforderlich. Sie können das Application-Objekt nicht direkt ansprechen, sondern nur über einen Stellvertreter, das heißt über eine Objektvariable. Sie muss mit dem Schlüsselwort WithEvents deklariert werden. Gehen Sie dazu wie folgt vor:

  • Starten Sie Word, laden Sie die Dokumentvorlage Normal.dot und starten Sie den VBA-Editor.

  • Wählen Sie im Projekt-Fenster den Eintrag ThisDocument aus, öffnen Sie das Codefenster und geben Sie folgenden Befehl ein:

    Private WithEvents wdApp As Word.Application
    
  • Öffnen Sie die linke Auswahlliste (die Objektauswahlliste) und wählen Sie die eben deklarierte Variable aus.

  • Öffnen Sie die rechte Auswahlliste (die Ereignisliste). Sie sehen jetzt alle Ereignisse, auf die das Application-Objekt reagieren kann.

Vermutlich werden Sie erfreut feststellen, dass diese Ereignisliste sehr viel reichhaltiger ist als beispielsweise die des Document-Objekts. Und genau in diesem Punkt hat es bei Office 2000 eine wichtige Verbesserung gegeben. Das Application-Objekt von Excel und Word wurde um einige Ereignisse erweitert, die die Flexibilität beim Programmieren steigern.
Es ist wichtig zu verstehen, welchen Unterschied es ausmacht, ob ein Ereignis zu einem Document- oder Worksheet-Objekt oder zum Application-Objekt gehört. Letztere Ereignisse werden global (bezogen auf die Anwendung) ausgelöst. Konkret bedeutet das, dass das DocumentBeforeSave-Ereignis des Application-Objekts immer dann ausgelöst wird, wenn eines der geöffneten Dokumente gespeichert werden soll. Es ist also mit wenig Aufwand möglich, eine Vorrichtung einzubauen, die zum Beispiel automatisch alle gespeicherten Dokumente mit zusätzlichen Informationen versieht, eine Sicherungskopie anfertigt, bestimmte Formatierungen oder andere Einstellungen überprüft und Vieles mehr.

Der Event-Handler

Bislang wurden die Ereignisse direkt in dem Modul abgefangen, in dem sie ausgelöst wurden. Im Folgenden wird gezeigt, wie sich ein globaler Event-Handler in einem Klassenmodul einrichten lässt (mit dem Begriff Handler werden Routinen bezeichnet, die sich um etwas kümmern, in diesem Fall um die Ereignisse). Als Anschauungsbeispiel dient Excel, das bereits bei der Version 97 in Bezug auf Ereignisse ergiebiger war als Word (Bild 3). Das folgende Beispiel zeigt die Anzahl der Zellen an, die ein Anwender markiert hat. Gehen Sie zur Umsetzung des Beispiels wie folgt vor:

Bild03
  • Starten Sie Excel (wahlweise Excel 97 oder Excel 2000) und den VBA-Editor.

  • Fügen Sie mit Hilfe des Menübefehls Einfügen/Klassenmodul ein Klassenmodul in das Projekt der aktuellen Arbeitsmappe ein und geben Sie ihm den Namen CEventHandler.

  • Öffnen Sie das Codefenster des Klassenmoduls und geben Sie den folgenden Befehl ein:

    Public WithEvents appExcel As Excel.Application
    

Damit wird eine öffentliche Variable als so genannte Ereignissenke (der Fachbegriff lautet event sink) deklariert, an die alle Ereignisse des Application-Objekts umgeleitet werden.

  • Öffnen Sie die linke Auswahlliste und wählen Sie den Eintrag appExcel. Öffnen Sie die rechte Auswahlliste und wählen Sie den Eintrag SelectionChange. Dadurch wird der Prozedurrahmen der Ereignisprozedur appExcel_SheetSelectionChange angezeigt. Geben Sie in die Prozedur den folgenden Befehl ein:

    MsgBox "Es wurden " & Target.Count & " _  
      Zellen selektiert!"
    

Er gibt den Wert der Count-Eigenschaft des über den Parameter Target übergebenen Range-Objekts aus.

  • Wählen Sie im Projekt-Explorer den Eintrag der Arbeitsmappe und zeigen Sie das Codefenster an.

  • Fügen Sie folgenden Befehl ein:

    Private objTest As CEventHandler
    

Er definiert eine Objektvariable vom Typ der zuvor angelegten Klasse.

  • Wählen Sie im Codefenster aus der linken Auswahlliste den Eintrag Workbook und aus der rechten Auswahlliste den Eintrag Open. Daraufhin wird der Eintrag der Ereignisprozedur Workbook_Open im Codefenster angezeigt. Geben Sie in die Prozedur folgende beiden Befehle ein:

    Set objTest = New CEventHandler 
    Set objTest.appExcel = Application
    

Diese Befehle instanzieren die Klasse CEventHandler und weisen der Variablen objTest das Application-Objekt zu. Damit ist der Event-Handler fertig. Damit er in Aktion treten kann, müssen Sie die Arbeitsmappe schließen (und dabei speichern, zum Beispiel unter EventTestMappe.xls) und anschließend erneut öffnen. Wenn Sie jetzt in einem der Tabellenblätter der Arbeitsmappe (das gilt auch für neu hinzugefügte Blätter) Zellen markieren, wird deren Anzahl angezeigt.

Soll die Ereignisauswertung beendet oder nur vorübergehend unterbrochen werden, muss die Objektvariable appExcel den Wert Nothing erhalten, was eine zusätzliche Prozedur in der Arbeitsmappe übernehmen kann:

Sub EventHandlerEnde() 
Set objTest.appExcel = Nothing 
End Sub


Sie kann zum Beispiel über ein Symbol in der Symbolleiste aufgerufen werden.

Folgende Besonderheiten gilt es im Zusammenhang mit dem WithEvents-Befehl zu berücksichtigen:

  • Der WithEvents-Befehl darf nur in einem Klassenmodul enthalten sein, also in einem Document- oder Worksheet-Modul oder in einem eingefügten Klassenmodul, nicht aber in einem allgemeinen Modul.

  • Soll der Event-Handler mit dem Start der Anwendung aktiv werden, muss er bei Word zum Beispiel im Document-Modul einer globalen Dokumentvorlage (entweder in der Normal.dot oder in einer Dokumentvorlage im Startup-Verzeichnis) oder bei Excel in einem Add-In enthalten sein.

  • Wird der WithEvents-Befehl in einem Klassenmodul untergebracht (und damit unabhängig von einem bestimmten Dokument), muss die Klasse instanziert und das Application-Objekt der Variablen, an die die Ereignisse umgeleitet werden, zugewiesen werden.

Rückmeldungen an die Anwendung

Moderne Ereignisprozeduren sind keine Einbahnstraße, sie erlauben in einigen Fällen auch eine Rückmeldung an die Anwendung. Ein naheliegendes Beispiel ist das DocumentBeforeClose-Ereignis, das – der Name verrät es bereits – auftritt, bevor ein Dokument geschlossen wird. Ist das aus irgendeinem Grund nicht erwünscht, kann dieser Vorgang durch ein VBA-Programm abgebrochen werden. Dazu muss die Ereignisprozedur folgenden Befehl enthalten:

Cancel = True


Bei Cancel handelt es sich um einen Prozedurparameter, der beim Aufruf der Prozedur übergeben und nach Verlassen der Prozedur von Word ausgewertet wird.

Ein abschließendes Beispiel

Das abschließende Beispiel, das den praktischen Nutzen der Ereignisse zeigt, setzt Word 2000 voraus. Über das DocumentBeforeClose-Ereignis wird in jedes Dokument vor dem Schließen in den ersten Absatz ein Zeitstempel eingetragen (Bild 4).

Bild04

Gehen Sie zur Umsetzung wie folgt vor:

  • Starten Sie Word und den VBA-Editor.

  • Wählen Sie im Projekt-Explorer das Projekt Normal.dot und in diesem Projekt das Modul ThisDocument aus. Die Befehle werden in die globale Dokumentvorlage eingefügt, damit sie für alle Dokumente gelten.

  • Fügen Sie in den Deklarationsbereich des Dokumentmoduls folgenden Befehl ein:

    Private WithEvents wdApp As Word.Application
    

Durch diesen Befehl wird die Objektvariable deklariert, die später die Ereignisse empfangen soll.

  • Wählen Sie aus der Objektliste im Dokumentmodulfenster den Eintrag wdApp und aus der Ereignisliste den Eintrag DocumentBeforeClose aus. Fügen Sie in die Ereignisprozedur die folgenden Befehle ein:

    With Doc.Paragraphs(1).Range 
    If InStr(.Text, "Letzte Änderung") = 0 Then 
    .InsertParagraphBefore 
    Selection.SetRange Start:=0, End:=0 
    Else 
    Selection.SetRange Start:=0, End:=.End - 1 
    End If 
    End With 
    Selection.Range.Text = "Letzte Änderung: " & _  
    Date & ":" & Format(Time, "Short Time")
    

Sie prüfen, ob der erste Absatz bereits den Text Letzte Änderung enthält. Ist das nicht der Fall, fügen sie einen neuen Absatz ein und tragen das aktuelle Datum in den ersten Absatz ein.

  • Wählen Sie aus der Objektliste im Dokumentmodulfenster den Eintrag Document und aus der Ereignisliste den Eintrag New aus. Fügen Sie in die Ereignisprozedur den folgenden Befehl ein:

    Set wdApp = Word.Application
    

Die Ereignisprozedur Document_New wird beim Anlegen eines neuen Dokuments ausgeführt. Sie sorgt dafür, dass die Objektvariable wdApp ihren Wert erhält.

  • Speichern Sie die Dokumentvorlage Normal.dot.

Wenn Sie jetzt ein neues Dokument anlegen, wird beim Schließen der Zeitstempel in das Dokument eingetragen.

Ausblick

In dieser Folge ging es um das ABC der Ereignisse der Office-Anwendungen. An dem Prinzip der Ereignisse hat sich bei Office 2000 im Vergleich zu Office 97 nichts geändert, allerdings wurde das Application-Objekt um zusätzliche Ereignisse erweitert, was eine flexiblere Programmierung ermöglicht. Auch im nächsten Beitrag geht es um die Ereignisse, allerdings aus einer anderen Perspektive. Sie lernen, wie Sie innerhalb eines Klassenmoduls mit den mit VBA 6.0 eingeführten Befehlen Event und RaiseEvent Ereignisse definieren und auslösen. Am Beispiel eines universellen Dateisuchprogramms, das, wann immer es eine Datei gefunden hat, ein Ereignis auslöst, wird diese leistungsfähige Programmiertechnik veranschaulicht.

Peter Monadjemi peterm@activetraining.de


Anzeigen: