Word bietet als Textverarbeitung ganz andere Möglichkeiten als Access-Berichte, wenn es um die Ausgabe von Texten geht. Natürlich liegen die Schwerpunkte bei Word auch ganz anders – so ist es grundsätzlich dafür ausgelegt, seine Texte nacheinander zu erfassen und nicht, wie etwa ein Access-Bericht, in einer durch die verschiedenen Berichtsbereiche vorgegebenen Struktur. Wir schauen uns in diesem Beitrag an, wie Sie Texte von Access nach Word bewegen und umgekehrt.
Im Gegensatz etwa zu Outlook ist Word eine Anwendung, von der man mehrere Instanzen erzeugen kann. Diese Erkenntnis ist wichtig, wenn Sie entscheiden, ob Sie für den VBA-gesteuerten Zugriff auf Word eine bestehende Instanz verwenden oder eine neue Instanz erstellen möchten. Dazu müssen Sie natürlich erst einmal herausfinden, ob auf dem Rechner bereits eine Word-Instanz geöffnet ist.
Da man grundsätzlich sagen kann, dass eine eigene Instanz einfacher zu handhaben ist, legen wir uns gleich darauf fest, jeweils eine eigene Instanz zu erzeugen. So können Sie diese Instanz bei der Erzeugung referenzieren und, wenn Sie diese nicht mehr benötigen, auch wieder beenden.
Wenn Sie von Access aus eine bestehende Instanz nutzen, müssten Sie sich diese gegebenenfalls mit einer anderen Anwendung teilen, die darauf zugreift, oder auch mit dem Benutzer, der gerade vor dem Rechner sitzt. Um eventuelle Seiteneffekte zu vermeiden, rufen wir für die Automation von Access aus lieber gleich eine eigene Instanz auf. Der einzige offensichtliche Nachteil ist, dass dies mehr Ressourcen benötigt als eine einzige Instanz.
Early Binding oder Late Binding
Die immerwährende Frage, ob Sie mit Early oder Late Binding arbeiten, kann man nur unter Betrachung des jeweiligen Kontext beurteilen. Wer eine Automation einer Office-Anwendung programmieren möchte, die unter allen gängigen Anwendungen läuft, sollte dies ohne Verwendung eines Verweises und dementsprechend mit Late Binding erledigen. Auf diese Weise verhindern Sie Probleme, die sonst beim Antreffen der falschen Version des Verweises auftreten.
Allerdings nehmen Sie sich damit auch die Möglichkeit, auf die Ereignisse zu reagieren, die vom Word-Objekt oder vom Document-Objekt ausgelöst werden. Interessant ist dies beispielsweise, wenn Sie beobachten wollen, ob der Benutzer ein Dokument öffnet oder schließt oder dieses speichert.
Sollten Sie solche Funktionen nutzen wollen, arbeiten Sie mit Early Binding, also unter Verwendung eines fest integrierten Verweises auf die jeweils aktuelle Version der Word-Objektbibliothek.
Diesen stellen Sie im Verweise-Dialog ein, den Sie über den Menüpunkt Extras|Verweise des VBA-Editors (Strg + G) öffnen – s. Bild 1. Anschließend können Sie mit der folgenden Anweisung eine Word-Instanz erstellen und mit einer entsprechenden Objektvariablen referenzieren:
Bild 1: Verweis auf die Word-Bibliothek
Dim objWord As Word.Application Set objWord = New Word.Application Sleep 3000 objWord.Quit Set objWord = Nothing
Dies erstellt eine Word-Instanz und schließt diese nach drei Sekunden wieder. Die gleiche Variante sieht beim Late Binding so aus:
Dim objWord As Object Dim objDocument As Object Set objWord = _ CreateObject("Word.Application") Set objDocument = objWord.Documents.Add
Um das Word-Fenster anzuzeigen und in den Vordergrund zu holen, sind ein paar Zeilen mehr nötig. Wir erzeugen zusätzlich ein neues, leeres Word-Dokument, machen die Word-Instanz mit der Visible-Eigenschaft sichtbar und holen das Anwendungsfenster mit der AppActivate-Methode nach vorn:
Dim objWord As Word.Application Dim objDocument As Word.Document Set objWord = New Word.Application Set objDocument = objWord.Documents.Add objWord.Visible = True AppActivate objDocument.Name Sleep 3000 objWord.Quit Set objWord = Nothing
Auch diese Instanz soll nach drei Sekunden wieder verschwinden. Sie können auch ohne explizites Erzeugen eines Word-Objekts ein Dokument in Word erzeugen oder öffnen. Das geht schlicht so:
Dim objDocument As Word.Document Set objDocument = New Word.Document objDocument.Parent.Visible = True AppActivate objDocument.Name Sleep 3000 objDocument.Close
Nach dem Schließen bleibt die Word-Instanz allerdings bestehen. Sie müssen diese dann manuell schließen oder per Code über die Parent-Eigenschaft des Word-Dokuments:
objDocument.Parent.Quit
Dazu muss das Dokument natürlich noch geöffnet sein. Wenn das Dokument vom Erzeugen beziehungsweise öffnen bis zum Schließen noch bearbeitet wird, erscheint beim Versuch, Word zu schließen, ein Dialog, der fragt, ob das Dokument gespeichert werden soll (s. Bild 2).
Bild 2: Rückfrage vor dem Schließen eines Dokuments
Dies können Sie verhindern, indem Sie festlegen, was beim Schließen geschehen soll: Soll Word das Dokument ohne Rückfrage speichern Oder die änderungen verwerfen Dies legen Sie mit einem der folgenden Werte für den ersten Parameter der Close-Methode des Document-Objekts fest:
- wdDoNotSaveChanges: Schließt das Dokument, ohne zu speichern.
- wdPromptToSaveChanges: Fragt den Benutzer, ob das Dokument gespeichert werden soll (Standardwert).
- wdSaveChanges: Speichert die änderungen.
Wenn Sie das Speichern-Verhalten auf diese Weise beeinflussen möchten, müssen Sie die Word-Instanz allerdings explizit instanzieren.
Anderenfalls könnten Sie diese nach dem Schließen des Document-Objekts nicht mehr refenzieren und müssten Word manuell schließen (sofern sichtbar) oder über den Task-Manager terminieren (wenn das Word-Fenster nicht eingeblendet wurde).
Wenn Sie selbst das Dokument per VBA mit Text füllen oder vorhandenen Text bearbeiten, werden Sie die änderungen vor dem Schließen speichern wollen:
Dim objWord As Word.Application Dim objDocument As Word.Document Set objWord = New Word.Application Set objDocument = objWord.Documents.Add objWord.Visible = True AppActivate objDocument.Name objDocument.Range = "Hallo" Sleep 3000 objDocument.Close, objWord.Quit Set objWord = Nothing
Haben Sie ein neues Dokument erstellt, wurde dies allerdings zuvor noch nicht gespeichert – ein Versuch, das Dokument zu schließen und automatisch zu speichern, schlägt fehl, da Word noch keinen Speicherort kennt. In diesem Fall speichern Sie es zuvor manuell unter dem gewünschten Namen. Dabei geben Sie optimalerweise direkt das gewünschte Format an, hier als Word-Dokument:
objDocument.SaveAs2 CurrentProject.Path & "\word.doc", wdFormatDocument
Dies verwendet das ältere .doc-Format. Wenn Sie das neue XML-Format verwenden möchten (Dateiendung .docx), verwenden Sie diese Anweisung:
objDocument.SaveAs2 CurrentProject.Path & "\word.docx", wdFormatXMLDocument
Beide Anweisungen speichern das Dokument im Verzeichnis der aktuellen Access-Datenbank.
Bestehendes Dokument öffnen
Sie können auch auf ein bereits bestehendes Dokument zugreifen. Dazu verwenden Sie die Open-Methode der Documents-Auflistung des Word-Objekts:
Set objDocument = objWord.Documents.Open(CurrentProject.Path & "\word.doc")
Auch dies gelingt mit Late Binding – in diesem Fall ohne vorherige Instanzierung eines Word-Objekts:
Set objDocument = GetObject( CurrentProject.Path & "\word.doc")
Sie müssen also einfach nur den Namen des zu öffnenden Dokuments als Parameter der GetObject-Methode angeben.
Text einfügen
Nachdem Sie ein Word-Dokument erstellt oder geöffnet haben, möchten Sie Text einfügen.
Dies gelingt am einfachsten, indem Sie dem mit der Range-Eigenschaft geliefernten Objekt des Word-Dokuments einen Text zuweisen:
objDocument.Range.Text = "Range-Objekt gefüllt"
Was aber ist dieses Range-Objekt überhaupt
Ein Range-Objekt markiert verschiedene Bereiche eines Dokuments. Das Range-Objekt des Document-Objekts etwa markiert den kompletten Inhalt. Wenn Sie der Text-Eigenschaft dieses Range-Objekts einen Text zuweisen, wird der komplette Bereich mit dem angegebenen Text überschrieben.
Sie können dies einfach experimentell prüfen, indem Sie eine Objektvariable für ein Document-Objekt im Kopf eines Standardmoduls deklarieren:
Public objDoc As Word.Document
Dieses füllen Sie dann mit der folgenden Prozedur:
Public Sub TextExperimente() Dim objWord As Word.Application Set objWord = New Word.Application Set objDoc = objWord.Documents.Add objWord.Visible = True AppActivate objDoc.Name End Sub
Das Dokument bleibt geöffnet und Sie können über das Direktfenster mit der Variablen objDoc auf das Dokument zugreifen.
Wenn Sie dort beispielsweise die folgende Zeile eingeben, wird der entsprechende Text angelegt (s. Bild 3):
Bild 3: Einfügen von Texten über den Direktbereich
objDoc.Range.Text = "Text aus dem Direktbereich"
Um zu erkennen, welchen Bereich die Range-Eigenschaft jeweils zurückgibt, können Sie den Bereich per VBA markieren:
objDoc.Range.Select
Die Markierung ist nicht direkt sichtbar, also aktivieren Sie entweder manuell das Word-Fenster oder Sie aktivieren dieses mit dieser Anweisung:
AppActivate objDoc.Name
Tippen Sie einmal einige Absätze in das Dokument und wiederholen das Markieren des Range-Objekts von objDoc, erkennen sie, dass dieses Range-Objekt immer den kompletten Dokumentinhalt betrifft.
Beim Experimentieren werden Fehler auftreten, was dazu führt, dass die Objektvariable objDoc ihren Inhalt verliert.
Mit der folgenden kleinen Prozedur füllen Sie diese wieder – vorausgesetzt, während der Experimente gibt es nur eine Word-Instanz mit nur einem Dokument (s. Listing 1).
Public Sub AktuellesDokumentReferenzieren() Dim objWord As Word.Application Set objWord = GetObject(, "Word.Application") Set objDoc = objWord.Documents(1) End Sub
Listing 1: Referenzieren des aktuellen Dokuments
Dokumentinhalt einlesen
Andersherum können Sie den Inhalt eines Range-Objekts auch über das Direktfenster auslesen. Dazu geben Sie beispielsweise mit der Debug.Print-Anweisung den Inhalt der Eigenschaft Text des aktuellen Range-Objekts aus.
Absätze
Ein Absatz in einem Word-Dokument ist ein Text, der mit dem Zeilenumbruch abgeschlossen wird, also dem Zeichen, das Sie unter VBA mit vbCr beziehungsweise Chr(13) darstellen können. Die durch dieses Zeichen voneinander getrennten Absätze können Sie mit der Paragraphs-Auflistung erfassen und mit einer Objektvariablen des Typs Paragraph referenzieren. In Bild 4 haben wir beispielsweise den Inhalt des zweiten Absatzes im Direktfenster ausgegeben.
Bild 4: Zugriff auf einen Absatz per Paragraphs-Auflistung
Wollen Sie den Text eines Absatzes verändern, können Sie diesen gezielt referenzieren und anpassen – und zwar so:
objdoc.Paragraphs(2).Range.Text = "Neuer Text in Absatz 2"
Das Ergebnis fällt allerdings nicht wie gewünscht aus: Der Text des zweiten Absatzes wird zwar ersetzt, aber der zweite Absatz verschmilzt mit dem dritten Absatz. Der Grund ist einfach: Sie haben einen Absatz, dessen Text mit einem Zeilenumbruch abgeschlossen wurde, durch einen Text ohne Zeilenumbruch ersetzt. Die folgende Anweisung ersetzt den Absatz schließlich wie gewünscht:
objDoc.Paragraphs(2).Range.Text = "Neuer Text in Absatz 2" & vbCr