Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Achtung: Dies ist nicht der vollständige Artikel, sondern nur ein paar Seiten davon. Wenn Sie hier nicht erfahren, was Sie wissen möchten, finden Sie am Ende Informationen darüber, wie Sie den ganzen Artikel lesen können.

Kompletten Artikel lesen?

Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

E-Mail:

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 3/2006.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Zusammenfassung

Erfahren Sie, wie Sie Word-Dokumente dynamisch erstellen.

Techniken

VBA, Word

Voraussetzungen

Access 2000 und höher

Beispieldatei

AccessToWord.mdb

Von Access nach Word

André Minhorst, Duisburg

"Von Access nach Word" - da kommt doch nicht zum x-ten Male diese (zugegebenermaßen oft gefragte) Serienbrief-Geschichte? Jein. Serienbriefe hat Access im Unternehmen (eigentlich) schon ausreichend behandelt. Welche Gründe soll es noch geben, Word zur Ausgabe von Access-Daten zu nutzen? Diese und die Frage nach der Umsetzung beantwortet der vorliegende Beitrag. Dabei erfahren Sie unter anderem, wie Sie Word starten und beenden, Dokumente und Bereiche referenzieren und diese mit den gewünschten Daten aus einer Access-Datenbank füllen.

Serienbrief & Co.

Serienbriefe sind - ganz klar - die Nummer Eins, wenn es um Anwendungen geht, die Access und Word miteinander verknüpfen. Ob die Access-Datenbank nun eine Tabelle oder Abfrage zum Füllen eines durch den Benutzer unter Word initiierten Serienbriefs liefert oder ob man diese Aufgabe von Access aus startet - das Thema ist in Newsgroups und Foren immer wieder gefragt. Das Prinzip dabei ist ganz einfach: Man definiert in Word ein paar Serienbrieffelder für Informationen, die sich von Brief zu Brief ändern: Adressdaten, Begrüßung, direkte Anrede im eigentlichen Text. Diese füllt man mit den passenden Inhalten aus der gewünschten Tabelle oder Abfrage.

Individualität in Serie

Dem Erzeuger eines solchen Dokuments spart dies eine ganze Menge Arbeit. Der Empfänger denkt sich nicht viel dabei, denn er ist es gewohnt, in Anschreiben persönlich angeredet zu werden. Was aber, wenn nicht nur Adresse und diverse Floskeln individuell gestaltet werden sollen, sondern noch mehr: Etwa, um einem Kunden interessante Produkte nahe zu bringen, zu denen er Informationen wünscht?

Man könnte meinen, das sei ja nicht viel anders als ein herkömmlicher Serienbrief: Jeder Kunde bekommt ja ohnehin ein individuelles Anschreiben, dann kann man auch den Inhalt individuell gestalten. Oder etwa nicht? Nun, soweit sich der Inhalt in ein oder mehrere Felder der verwendeten Datenherkunft quetschen lässt, ist das kein Problem. Wenn auf diese Weise etwa mehrere Produktbeschreibungen integriert werden sollen, die mehr als den reinen Beschreibungstext enthalten - also beispielsweise eine Überschrift mit dem Produktnamen, eine Abbildung oder Informationen wie Preis oder Lieferzeit - wird es hingegen schwierig: Das Ganze mag für ein einziges Produkt funktionieren, weil man dann für jedes Feld eine eigene Formatierung festlegen kann.

Wenn aber jedes Anschreiben mehrere Produkte enthalten soll, wird es problematisch: Die Anzahl der Felder lässt sich nämlich nicht dynamisch anpassen wie etwa im Detailbereich eines Berichts, der die Datensätze einfach untereinander weg schreibt.

Das Problem lässt sich genauer umreißen: Dies ist der Versuch, das Ergebnis der Abfrage über zwei Tabellen mit einer m:n-Beziehung in einem Word-Dokument abzubilden, wobei die eine Seite der Beziehung die Tabelle der Empfänger und die andere Seite die Produkttabelle ist (bei einer 1:n-Beziehung wäre die Darstellung im Übrigen nicht wesentlich einfacher - Beispiel Kategorien und Artikel).

VBA kann alles

Ohne die komfortable Serienbrieffunktion wird es eng: Auch das programmatische Füllen einer Dokumentenvorlage mit vorbereiteten Textmarken scheitert zunächst, da auch hier die Anzahl der für die Anzeige des Produkts benötigten Absätze nicht ohne Weiteres dynamisch einstellbar ist.

Zum Glück können Sie unter Word VBA einsetzen und genauso können Sie Word von Access aus per VBA fernsteuern. Das ist die Grundlage für die nachfolgend vorgestellten Techniken.

Word starten und beenden

Zum Fernsteuern von Word legen Sie am besten zunächst einen Verweis auf die passende Objektbibliothek an (s. Abb. 1).

Hinweis

Sie kommen zwar auch ohne aus, wenn Sie Late Binding verwenden möchten (mehr dazu siehe Hinweis), aber zum Entwickeln sollten Sie die Vorzüge des Early Bindings (deutsch: frühe Bindung) genießen: Dazu gehört unter anderem die Unterstützung von IntelliSense für die Elemente der referenzierten Bibliothek.

Abb. 1: Herstellen eines Verweises auf die Word-Objektbibliothek

Hinweis

Early Binding (also das Setzen eines Verweises und das Verwenden konkreter Objekte) setzt voraus, dass die verwendeten Bibliotheken auf allen Zielrechnern vorhanden sind. Sicherer ist der Einsatz von Late Binding: Dabei lassen Sie den Verweis weg und verwenden jeweils den Datentyp Object statt eines konkreten Typs wie etwa Word.Application bei der Deklaration. Wenn Sie eine Anwendung von Early Binding auf Late Binding umstellen, müssen Sie außerdem berücksichtigen, dass die sprechenden Konstanten nicht mehr zur Verfügung stehen. Statt dessen verwenden Sie die konkreten Zahlenwerte. Welcher Zahlenwert welcher Konstante entspricht, erfahren Sie im Objektkatalog: Suchen Sie einfach nach der gewünschten Konstanten und lesen Sie im unteren Bereich den Zahlenwert ab - in Abb. 2 ist dies beispielsweise der Wert -2 für die Konstante wdBorderLeft. Um sicherzugehen, dass Sie alle Konstanten durch die passenden Zahlenwerte ersetzt haben, kompilieren Sie einfach die Anwendung. Option Explicit sollte dabei allerdings aktiviert sein. (

Die Routine aus Quellcode 1 arbeitet zunächst nur mit der Word-Anwendung, ohne irgendwelche Dokumente zu öffnen. Dabei deklariert sie eine Objektvariable für den Verweis auf die gewünschte Instanz von Word.

Offen ist noch, wie man an diese Instanz kommt: Gegebenenfalls ist Word schon geöffnet. In diesem Fall verwendet man diese Instanz und stellt die Variable objWord mit der GetObject-Methode auf diese Instanz ein. Es kann natürlich auch sein, dass Word noch nicht geöffnet ist: Dann startet die Routine mit CreateObject eine neue Instanz und verweist mit objWord auf diese.

Abb. 2: Ermitteln des Wertes einer Konstanten im Objektkatalog

Der Clou dieser Routine ist, dass die Suche nach einer vorhandenen Instanz am einfachsten über das Provozieren eines Fehlers möglich ist: Vor dem Versuch, eine bestehende Instanz zu referenzieren, stellt die Routine die Fehlerbehandlung so ein, dass diese beim Auftreten eines Fehlers einfach zum nächsten Befehl springt.

Diese Anweisung prüft, ob die Eigenschaft Number des Err-Objekts einen Wert größer 0 hat - was auf das Auftreten eines Fehlers hinweist. Dieser kann eigentlich nur durch das Scheitern der Herstellung eines Verweises auf eine bestehende Word-Instanz entstanden sein, woraufhin die Routine eine neue Instanz erzeugt.

Tritt kein Fehler auf, was beim "Übernehmen" einer bestehenden Instanz von Word der Fall ist, aktiviert die Routine diese.

Zwischen der With- und der End With-Zeile findet die eigentliche Fernsteuerung (Automation) von Word statt. Hier ist Platz zum Öffnen oder Anlegen eines Word-Dokuments, für seine Bearbeitung und das Schließen des Dokuments.

Zu guter Letzt beendet die Routine die Word-Instanz.

Quellcode 1: Initialisieren von Word und anschließendes Beenden

Public Sub WordInitialisieren()

    Dim objWord As Word.Application

    On Error Resume Next

    Set objWord = GetObject(, _
        "Word.Application")

    If Err.Number > 0 Then

        On Error Goto 0

        Set objWord = _
            CreateObject("Word.Application")

    Else

        objWord.Activate

    End If

    With objWord

        .Visible = True

        'Word etwas tun lassen

    End With

    objWord.Quit

    Set objWord = Nothing

End Sub

Dokument referenzieren

Es gibt drei Möglichkeiten, um an ein Dokument zum Eintragen von Daten zu kommen:

  • Anlegen eines neuen Dokuments ohne Vorlage
  • Anlegen eines neuen Dokuments mit Vorlage
  • Öffnen eines bestehenden Dokuments
  • Alle drei Varianten erfordern das Vorhandensein einer Objektvariablen, mit der Sie auf das Dokument verweisen, um es anschließend bearbeiten, drucken, speichern oder schließen zu können. Fügen Sie daher die folgende Zeile zu der Routine aus Quellcode 1 hinzu:

    Dim objDocument As Word.Document

    Neues Dokument ohne Vorlage anlegen

    Die folgenden Zeilen fügen Sie in Quellcode an der Stelle ein, an der sich der Kommentar "Word etwas tun lassen" befindet:

    Set objDocument = .Documents.Add

    objDocument.SaveAs "c:\test.doc"

    objDocument.Close

    Dies legt ein neues Word-Dokument ohne Vorlage an, speichert es unter dem Dateinamen c:\test.doc und schließt das Dokument wieder.

    Neues Dokument unter Verwendung einer Vorlage anlegen

    Die Add-Methode der Documents-Auflistung von Word bietet einen Parameter zum Angeben der gewünschten Formatvorlage. Wenn Sie die Add-Methode wie folgt ergänzen, legt Word ein neues Dokument auf Basis der angegebenen Formatvorlage an (in einer Zeile):

    Set objDocument = .Documents.Add("MeineFormatvorlage.dot")

    Dabei geht Word davon aus, dass sich die Formatvorlage im Vorlagenverzeichnis befindet. Welches das ist, finden Sie mit folgender Anweisung, abgesetzt im Direktfenster, heraus:

    Debug.Print Word.Options.DefaultFilePath
    (Path:= wdUserTemplatesPath)

    Bestehendes Dokument öffnen

    Das Öffnen eines bestehenden Dokuments ist ebenfalls ganz einfach. In diesem Fall verwenden Sie die Open-Methode der Documents-Auflistung:

    Set objDocument = .Documents.Open("c:\test.doc")

    Vom Makro lernen

    VBA-Prozeduren nennt man in Word Makros (in den anderen Office-Anwendungen außer Access übrigens auch). Die von Access bekannten Makros haben damit also nichts gemein.

    Makros von Word & Co. haben einen entscheidenden Vorteil: Sie können viele Ihrer Tätigkeiten mit Word damit aufzeichnen und sich anschließend den so generierten VBA-Code ansehen und diesen anpassen.

    Wer sich nicht gut mit dem Objektmodell etwa von Word auskennt, findet hier einen guten Einstieg. Das Aufnehmen eines Makros geht ganz einfach:

  • Wählen Sie in Word den Menüeintrag Extras/Makro/Aufzeichnen... aus und bestätigen Sie den nun erscheinenden Dialog mit der Schaltfläche OK, nachdem Sie gegebenenfalls einen alternativen Makro-Namen eingegeben haben (s. Abb. 3).
  • Führen Sie die gewünschten Aktionen aus - legen Sie ein neues Dokument an, fügen Sie Text hinzu oder was Ihnen sonst gerade einfällt.
  • Klicken Sie auf die Schaltfläche Aufzeichnung beenden der Mini-Menüleiste, die nach dem Start der Aufzeichnung erscheint. (
  • Abb. 3: Eigenschaften eines aufzunehmenden Makros festlegen

    Fertig! Sie müssen nun noch mit Alt + F11 die VBA-Entwicklungsumgebung öffnen und im Projekt-Explorer das Modul Normal/Module/NewMacros auswählen - Word legt Makros standardmäßig an diesem Ort in der Formatvorlage Normal.dot an (s. Abb. 4).

    Eine große Hilfe bei Programmierfragen zu Word-VBA ist die FAQ von René Probst unter folgender Adresse: http://mypage.bluewin.ch/
    reprobst/WordFAQ/VBA.htm

    Die Inhalte dieser Seite verdeutlichen, dass der mit dem Makrorekorder erzeugte Code nur suboptimal ist - so wird dort überwiegend mit dem Selection-Objekt gearbeitet, das gut geeignet ist, die manuell vorgenommenen Änderungen am Dokument aufzuzeichnen. Viel mächtiger und schneller ist jedoch das Range-Objekt, mit dem sich Bereiche direkt ansprechen lassen.

    Dadurch fällt das für das Selection-Objekt typische Navigieren weg - wer programmiert, will schließlich zielgerichtet arbeiten und nicht hier und da ein Zeichen einfügen, bis das Dokument fertig gestellt ist.

    Außerdem ist es bei der Programmierung von Word per VBA wichtig, sich das Word-Dokument nicht als Objekt mit Seiten und Zeilen vorzustellen - diese lassen sich nämlich per VBA ganz schlecht erfassen.

    Abb. 4: Anzeigen eines frisch aufgezeichneten Makros im VBA-Editor unter Word

    Bericht oder Word-Dokument?

    Und damit bekommt die Idee, statt eines Berichts ein Word-Dokument zur Ausgabe der in Tabellen gespeicherten Daten zu verwenden, einen herben Rückschlag: Wenn man nicht weiß, wann eine neue Seite beginnt, wie soll man dann etwa eine Zeile mit einer Zwischensumme (beispielsweise einer Rechnung) zuverlässig positionieren?

    Sie sollten also sorgsam abwägen, ob Sie sich mit Word als "Report-Engine" aller Sorgen entledigen, die Sie möglicherweise mit Access-Berichten haben. In vielen Fällen lässt sich aus diesen nämlich weit mehr herausholen, als man erwartet.

    Die Formatierungsmöglichkeiten von Word sind natürlich unschlagbar; allerdings werden Sie den Inhalt einer Tabelle beim automatischen Export nicht mehr und nicht weniger formatieren können als in einem Bericht: Der Feldinhalt ist eben die kleinste Einheit, was die Formatierung angeht.

    Die einzige Alternative ist der Einsatz von RTF-Texten: Damit können Sie auch Teile des in einem Tabellenfeld enthaltenen Textes nach Wunsch formatieren. Dieses Thema behandeln wie in einer der nächsten Ausgaben.

    Leeres Dokument mit Text
    füllen

    Wenn Sie einfach nur ein leeres Dokument mit den in einer Tabelle enthaltenen Daten füllen möchten, benötigen Sie kein Range-Objekt: Dann schreiben Sie einfach die Daten herunter - Feld für Feld, Datensatz für Datensatz.

    Text ohne Formatierung einfügen

    Die Routine aus Quellcode 2 schreibt Namen und Positionen aller Mitarbeiter der Nordwind-Datenbank in ein neues Word-Dokument
    (s. Abb. 5).

    Dazu deklariert und instanziert es ein Recordset-Objekt mit den Datensätzen der Personal-Tabelle.

    Abb. 5: Ein per VBA-Code gefülltes Word-Dokument

    Quellcode 2: Schreiben von Daten in ein leeres Word-Dokument

    Public Sub PersonaldatenSchreiben()

        Dim objWord As Word.Application

        Dim objDocument As Word.Document

        Dim db As DAO.Database

        Dim rst As DAO.Recordset

        Set db = CurrentDb

        Set rst = db.OpenRecordset("Personal", dbOpenDynaset)

        On Error Resume Next

        Set objWord = GetObject(, "Word.Application")

        If Err.Number > 0 Then

            On Error GoTo 0
            Set objWord = CreateObject("Word.Application")

        Else

            objWord.Activate

        End If

        With objWord

            .Visible = True

            Set objDocument = .Documents.Add

            Do While Not rst.EOF

                .Selection.TypeText rst!Vorname & " " _
                    & rst!Nachname & " (" & rst!Position & ")" _
                    & vbCrLf

                rst.MoveNext

            Loop

            objDocument.SaveAs "e:\test.doc"

            objDocument.Close

        End With

        objWord.Quit

        Set objWord = Nothing

    End Sub

    Dieses durchläuft die Routine und schreibt dabei einige Informationen mit der TypeText-Methode des Selection-Objekts in die Word-Datei. Das Selection-Objekt entspricht dabei der Position der Einfügemarke, die sich beim Verwenden der TypeText-Methode jeweils hinter den geschriebenen Text verschiebt.

    Text mit Formatierung einfügen

    Wenn Sie die einzelnen Elemente (sprich: Felder der zugrunde liegenden Datenquelle) unterschiedlich formatieren möchten, bietet sich der Einsatz des Range-Objekts an.

    Die Routine aus Quellcode 3 zeigt ein Beispiel. Es soll die gleiche Ausgabe wie die vorherige Prozedur erzeugen, aber die Mitarbeiternamen fett drucken und dazu das Range-Objekt verwenden.

    Das Range-Objekt wird zunächst auf den letzten Absatz gesetzt. Wenn der Absatz keinen Zeilenumbruch enthält (Chr(13)), wird ein solcher zunächst am Ende eingefügt und das Range-Objekt auf die neue, leere Zeile gesetzt.

    Die InsertAfter-Methode des Range-Objekts fügt dann zunächst den Vor- und Nachnamen des Mitarbeiters in das Dokument ein. Dies erweitert das Range-Objekt entsprechend vom Anfang der neuen Zeile bis zum letzten Zeichen des eingefügten Textes, sodass dieser leicht über rng.Font.Bold in fett gedruckten Text umgewandelt werden kann. Wenn man jetzt weiteren Text hinter dem aktuellen Text anfügt, wird dieser ebenfalls fett hervorgehoben.

    Also verschieben Sie den Beginn des Range-Objekts auf das Ende des aktuellen Range-Objekts, aber vor das Zeilenumbruch-Zeichen (rng.End -1) und fügen dort in Klammern die Position des aktuellen Mitarbeiters ein (rng.InsertAfter...). Dieser ist zwar immer noch fett gedruckt, aber Sie haben ja einen neuen Range festgelegt, der die Angabe der Position umfasst: Und diesen Bereich können Sie leicht mit rng.Font.Bold = False wieder auf normale Strichstärke einstellen. Das Ergebnis sieht diesmal wie in Abb. 6 aus.

    Abb. 6: Automatisch generiertes Word-Dokument mit individueller Formatierung

    Quellcode 3: Einsatz des Range-Objekts zum Formatieren von Texten

    Public Sub PersonaldatenSchreibenMitFormat()

        ...    

        Dim rng As Word.Range

        ...

        With objWord

            .Visible = True

            Set objDocument = .Documents.Add

            Do While Not rst.EOF

                Set rng = .ActiveDocument.Range.Paragraphs.Last.Range

                If Not rng.Text = Chr(13) Then

                    .ActiveDocument.Range.InsertAfter Chr(13)

                    Set rng = .ActiveDocument.Range.Paragraphs.Last.Range

                End If

                rng.InsertAfter rst!Vorname & " " & rst!Nachname

                rng.Font.Bold = True

                Set rng = .ActiveDocument.Range(rng.End - 1, rng.End)

                rng.InsertAfter " (" & rst!Position & ")"

                rng.Font.Bold = False

                rst.MoveNext

            Loop

            objDocument.SaveAs "e:\test.doc"

            objDocument.Close

        End With

        ...

    End Sub

    Quellcode 4: Schreiben von Daten aus einer Access-Tabelle in eine Word-Tabelle

    Public Sub PersonaldatenInTabelle()

        ...

        Dim cel As Word.Cell

        Dim col As Word.Column

        Dim tbl As Word.Table

        ...

        With objWord

            .Visible = True

            Set objDocument = .Documents.Add

            Set rng = .Selection.Range

            Do While Not rst.EOF

                rng.InsertAfter rst!Vorname & vbTab & rst!Nachname & vbTab & rst!Position & vbCrLf

                rst.MoveNext

            Loop

            Set tbl = rng.ConvertToTable(vbTab)

            'Tabelle formatieren

            For Each col In tbl.Columns

                For Each cel In col.Cells

                    cel.Borders(wdBorderLeft).LineStyle = wdLineStyleSingle

                    cel.Borders(wdBorderRight).LineStyle = wdLineStyleSingle

                    cel.Borders(wdBorderTop).LineStyle = wdLineStyleSingle

                    cel.Borders(wdBorderBottom).LineStyle = wdLineStyleSingle

                Next cel

            Next col

            objDocument.SaveAs "e:\test.doc"

            objDocument.Close

        End With

        ...

    End Sub

    Texte in Tabelle

    Vielleicht möchten Sie auch - der besseren Übersicht halber - die Mitarbeiterdaten in eine Word-Tabelle schreiben.

    Das geht am allerschnellsten, wenn Sie die Daten einer Zeile erst einmal durch ein bestimmtes Steuerzeichen getrennt (etwa vbTab für Tabulator) in das Word-Dokument schreiben und dann den ganzen Bereich mit der Methode ConvertToTable in eine Tabelle konvertieren.

    Anschließend durchläuft die Routine aus Quellcode 4 die Tabelle in zwei For Each-Schleifen und fügt jeder Zelle einen Rahmen hinzu.

    Die Tabelle sieht dann wie in Abb. 7 aus.

    Abb. 7: Aus der Tabelle in die Tabelle: Access-Daten in einer Word-Tabelle

    Dokument auf Basis einer
    Dokumentvorlage füllen

    Das Verwenden einer Dokumentvorlage zum Füllen eines Word-Dokuments bringt mehrere Vorteile:

  • Die gewünschten Formatvorlagen können vorab definiert werden.
  • Sie können Textmarken einfügen, die als Platzhalter für die einzufügenden Texte dienen.
  • Für gleichartige Dokumente benötigte Inhalte brauchen nur einmal festgelegt zu werden (etwa Briefkopf, Absenderadresse oder Text bei Serienbriefen).
  • Sie haben das Ende des frei verfügbaren Teils des Artikels erreicht. Lesen Sie weiter, um zu erfahren, wie Sie den vollständigen Artikel lesen und auf viele hundert weitere Artikel zugreifen können.

    Sind Sie Abonnent?Jetzt einloggen ...
     

    Kompletten Artikel lesen?

    Einfach für den Newsletter anmelden, dann lesen Sie schon in einer Minute den kompletten Artikel und erhalten die Beispieldatenbanken.

    E-Mail:

    © 2003-2015 André Minhorst Alle Rechte vorbehalten.