PDF-Erzeugung – Teil 2

15.10.2006 von Helma  Spona
Der aktuelle Teil der Artikelfolge stellt zwei Komponenten vor, mit denen Sie PDF-Dateien erstellen können, ohne zuvor einen Bericht erzeugen zu müssen, den Sie anschließend ausdrucken. Der Einsatz dieser Tools ist nicht ganz so einfach wie bei AD-PDFPrint.DLL, das Sie bereits kennen gelernt haben, dafür aber flexibler.

Die Installation der ersten hier betrachteten Komponente, PDF Creator Pilot, erfolgt über ein dialoggesteuertes Setup-Programm. Danach müssen Sie den Rechner neu starten.

Vorbereitungen

Damit Sie die Komponente verwenden können, ist ein Verweis auf die Bibliothek PDF Creator Pilot (PDFCreatorPilot.dll) erforderlich, den Sie über Extras/Verweise im Menü der Entwicklungsumgebung erstellen.

Um eine PDF-Datei erzeugen zu können, erstellen Sie zunächst das Objekt aus der Komponente. Anschließend rufen Sie die StartEngine- Methode auf und übergeben eine E-Mail-Adresse und ein Kennwort, um die Komponente zu initialisieren.

Falls Sie möchten, dass die PDF-Datei automatisch geöffnet und angezeigt wird, sobald sie erzeugt ist, setzen Sie die AutoLaunch-Eigenschaft auf True. Das Dokument beginnen Sie anschließend, indem Sie den Dateinamen und den Pfad über die FileName-Eigenschaft festlegen und danach die BeginDoc-Methode aufrufen.

Bevor Sie den Text ausgeben können, müssen Sie mit der PDFPAGE_SetActiveFont-Methode die Schriftart und Größe sowie weitere Formatierungen der Schrift definieren. Danach erfolgt die Textausgabe mit der Methode PDFPAGE_ TextOut, der Sie die Position und den Text übergeben. Mit der EndDoc-Methode wird die Datei gespeichert und die PDF-Erzeugung abgeschlossen. Haben Sie die AutoLaunch-Eigenschaft auf True gesetzt, wird die erzeugte PDFDatei nun angezeigt.

Bei Verwendung der Testversion beziehungsweise der nicht registrierten Version der Komponente erscheint beim Öffnen einer damit erzeugten PDF-Datei eine Meldung, die erst geschlossen werden muss. Außerdem wird im Hintergrund der PDF-Datei ein Hinweis auf die Demoversion eingefügt.

Bild 1: Das mit dem PDF Creator Pilot erzeugte PDF-Dokument.

Sub PDFAusgabe()
Dim objPDF As PDFCreatorPilot2.piPDFDocument
Set objPDF = New piPDFDocument
Dim strName As String
strName = getDBPfad() & "PDFCreatorDemo.pdf"
With objPDF
'PDF-Datei erzeugen
'Initialisieren
.StartEngine "demo@demo", "demo"
'PDF-Datei im Anschluss öffnen
.AutoLaunch = True
'Dateiname festlegen
.FileName = strName
'Dokument erstellen
.BeginDoc
'Schriftart und Größe festlegen
.PDFPAGE_SetActiveFont "Verdana", True, False, False, False, 14, 0
'Testausgeben
.PDFPAGE_TextOut 10, 20, 0, "Dies ist der ausgegebene Text!"
'Dokument abschließen und speichern
.EndDoc
End With
Set objPDF = Nothing
End Sub

Programm-Info

Name: PDF Creator Pilot
Hersteller: Two Pilots (http://www.colorpilot.com)
Preis: ab ca. 1000 Euro
Ermöglicht eine recht einfache Erzeugung von PDF-Dokumenten „on the fly“ und deren automatische Anzeige im Anschluss.

Ausgabe als Tabelle

Das Beispiel in Listing 2 zeigt, wie Sie den Inhalt einer Datensatzgruppe als Tabelle ausgeben. Dazu ist es notwendig, zunächst das Recordset- Objekt zu erzeugen und die Datensatzgruppe in einer Schleife zu durchlaufen.

Sub ListeAusgeben()
Dim strSQL As String
Dim objPDF As PDFCreatorPilot2.piPDFDocument
Dim objRS As ADODB.Recordset
Set objRS = New ADODB.Recordset
Set objPDF = New piPDFDocument
Dim strName As String
Dim lngX As Long
Dim lngY As Long
Dim objFeld As ADODB.Field
Const lngZeilenabstand = 2
lngX = 10
lngY = 10
strName = getDBPfad() & "PDFCreatorListe2.pdf"
strSQL = "SELECT * FROM Daten"
'SQL-Anweisung ausführen
objRS.Open strSQL, Application.CurrentProject.Connection, adOpenStatic
'PDF-Datei erstellen
If objRS.RecordCount > 0 Then
With objPDF
'PDF-Datei erzeugen
'Initialisieren
.StartEngine "demo@demo", "demo"
'PDF-Datei im Anschluss öffnen
.AutoLaunch = True
'Dateiname festlegen
.FileName = strName
'Dokument erstellen
.BeginDoc
'Schriftart und Größe festlegen
.PDFPAGE_SetActiveFont "Verdana", True, False, False, False, 18, 0
'Überschrift ausgeben
.PDFPAGE_TextOutBox lngX, lngY, 0, 1000, 20, "DATEN"
'Schrift für die Liste festlegen
.PDFPAGE_SetActiveFont "Verdana", True, False, False, False, 14, 0
'Alle Datensätze durchlaufen
objRS.MoveFirst
Do While objRS.EOF = False
lngY = lngY + (14 * lngZeilenabstand)
'alle Felder durchlaufen
For Each objFeld In objRS.Fields
.PDFPAGE_TextBox lngX, lngY, lngX + (.PDFPAGE_Width \ _
objRS.Fields.Count), lngY + 14, objFeld.Value, hjLeft, vjCenter
lngX = lngX + (.PDFPAGE_Width \ objRS.Fields.Count)
Next objFeld
lngX = 10
objRS.MoveNext
Loop
'Dokument abschließen und speichern
.EndDoc
End With
End If
End Sub

Damit dann auch unabhängig von den Feldern der Abfrage alle Daten ausgegeben werden, müssen Sie noch innerhalb der Do-While-Schleife alle Felder in einer For-Each-Schleife durchlaufen. Geben Sie Text mit der TextOutBox- Methode aus, müssen Sie ihn jedoch exakt positionieren. Das heißt, die Komponente sorgt nicht selbst dafür, dass die Textboxen nebeneinander angeordnet werden.

Sie müssen daher sowohl die X- wie die Y-Position der Ausgabe über entsprechende Variablen festlegen. Die Variable lngX bestimmt die horizontalePosition, die Variable lngY die vertikale Position der Ausgabe.

Die Do-Loop-Schleife

Innerhalb der Schleife müssen Sie dann nur nach jedem Feld den X-Wert erhöhen und nach jeder Zeile den Y-Wert erhöhen und den X-Wert wieder auf den Anfangswert 10 zurücksetzen. Die XPosition der einzelnen Felder hängt davon ab, wie viele Felder es gibt. Hier wird einfach die Breite der Seite, die über die .PDFPAGE_Width ausgelesen werden kann, durch die Anzahl Felder der Datensatzgruppe geteilt. Dieser Wert definiert den Endpunkt der Textbox und legt gleichzeitig den Anfang der nächsten Box fest, indem der Wert der Variablen lngX um den entsprechenden Wert erhöht wird.

Die Darstellung lässt noch etwas zu wünschen übrig (Listing 2). Wenn Sie jede zweite Zeile grau unterlegen möchten, müssen Sie dazu vor Ausgabe des Textes ein entsprechend großes Rechteck zeichnen.

Möchten Sie Rechtecke erzeugen und füllen, abwechselnd grau und weiß, müssen Sie zunächst bei der Ausgabe die Zeilen zählen, um dann vor jeder Ausgabe prüfen zu können, ob es sich um eine gerade oder ungerade Zeilennummer handelt. Dazu definieren Sie eine Variable lngZeile und zählen sie hoch.

Innerhalb der Do-Loop-Schleife prüfen Sie dann, ob lngZeile Mod 2 gleich 1 ist. In diesem Fall legen Sie als Füllfarbe ein helles Grau mit der Methode PDFPAGE_SetGrayFill fest. Als Wert übergeben Sie einen Wert zwischen 0 und 1 an die Methode. Je höher der Wert, desto heller ist das Grau.

Anschließend zeichnen Sie das Rechteck, das sich über die ganze Seitenbreite erstrecken soll, übergeben Sie 0 und die VariablenlngY-2 als Endposition, die Seitenbreite und die Variable lngY abzüglich 2 und zuzüglich der aus Schriftgröße und Zeilenabstand berechneten Zeilenhöhe.

Die Subtraktion von 2 ist zu empfehlen, damit die Schrift mittig innerhalb des Rechtecks angeordnet wird. Damit das gezeichnete Rechteck mit der definierten Füllfarbe gefüllt wird, müssen Sie dann die Fill-Methode aufrufen. Ganz wichtig isthierbei die Reihenfolge:

Eine andere Reihenfolge führt zu Laufzeitfehlern.

Vor der Textausgabe

Bevor Sie dann allerdings Text ausgeben, sollten Sie die Füllfarbe wieder auf Schwarz zurücksetzen. Die Schrift wäre sonst in der gleichen Farbe und auf dem Hintergrund nicht sichtbar. Dazu rufen Sie einfach wieder die Methode PDFPAGE_SetGrayFill auf und übergeben als Wert 0. Nun fehlen noch die Linien. Es soll unterhalb der Überschrift und am Ende der Liste als Abschluss eine Linie gezeichnet würde. Linien zeichnen Sie mit der PDFPAGE_LineTo-Methode. Allerdings können Sie der Methode nur die Zielposition übergeben. Die Anfangsposition sowie die Eigenschaften der Linie müssen Sie zuvor festlegen. Die PDFPAGE_MoveTo-Methode setzt die aktuelle Ausgabeposition, an der die Linie beginnt. Mit PDFPAGE_SetGrayStroke können Sie einen Grauton für die Linie festlegen, und die Methode PDFPAGE_Stroke sorgt nach dem Zeichnen der Linie dafür, dass die Linie mit der gesetzten Rahmenfarbe gezeichnet wird.

Ein Problem sind noch mögliche Laufzeitfehler. Wenn es aus irgendeinem Grund dazu kommt, dass die Codeausführung abgebrochen wird, nachdem die Datei mit BeginDoc geöffnet und bevor sie mit EndDoc wieder geschlossen wurde, führt das dazu, dass die Datei in Windows noch als geöffnet markiert ist. Sie können sie dann weder beim nächsten Start überschreiben noch löschen, auch nicht umbenennen oder verschieben. Daher ist es ganz wichtig, dass Sie in einer Fehlerbehandlungsroutine dafür sorgen, dass bei Auftreten eines Laufzeitfehlers das Dokument geschlossen wird, bevor Sie die Prozedur verlassen. Nach Aufruf der BeginDoc-Methode müssen Sie dazu die Anweisung On Error Goto FEHLER einfügen. Am Ende, direkt vor der End- Doc-Methode, definieren Sie dann noch die Sprungmarke FEHLER.

Bild 2: Die erzeugte Liste.

Sub ListeAusgeben()
Dim strSQL As String
Dim objPDF As PDFCreatorPilot2.piPDFDocument
Dim objRS As ADODB.Recordset
Set objRS = New ADODB.Recordset
Set objPDF = New piPDFDocument
Dim strName As String
Dim lngX As Long
Dim lngY As Long
Dim objFeld As ADODB.Field
Dim lngZeile As Long
lngZeile = 0
...
If objRS.RecordCount > 0 Then
...
Do While objRS.EOF = False
lngY = lngY + (14 * lngZeilenabstand)
'Rechteck ausgeben
lngZeile = lngZeile + 1
If lngZeile Mod 2 Then
.PDFPAGE_SetGrayFill 0.9
Else
.PDFPAGE_SetGrayFill 1
End If
.PDFPAGE_Rectangle 0, lngY - 2,
.PDFPAGE_Width, lngY - 2 + (14 * lngZeilenabstand)
.PDFPAGE_Fill
.PDFPAGE_SetGray 0
'alle Felder durchlaufen
For Each objFeld In objRS.Fields
.PDFPAGE_TextBox lngX, lngY, lngX + (.PDFPAGE_Width \ _
objRS.Fields.Count), lngY + 14, objFeld.Value, hjLeft, vjCenter
lngX = lngX + (.PDFPAGE_Width \ objRS.Fields.Count)
Next objFeld
lngX = 10
objRS.MoveNext

Der Amyuni-PDFCreator

Das zweite hier vorgestellte Tool ist der Amyuni- PDF-Creator. Dabei handelt es sich um eine professionelle Komponente, die zwar nicht kostenlos ist, dafür aber eine Menge bietet und zu moderaten Preisen zu haben ist. Die Testversion ist daran erkennbar, dass über den Inhalt der PDF-Datei eine rote Schrift mit einem Hinweis auf die Testversion gelegt wird.

Sub ListeAusgeben()
...
'Überschrift ausgeben
.PDFPAGE_TextOutBox lngX, lngY, 0, 1000, 20, "DATEN"
'Linie unter der Überschrift zeichnen
.PDFPAGE_SetLineWidth 1
.PDFPAGE_SetGrayStroke 0.5
.PDFPAGE_MoveTo 0, lngY + 25
.PDFPAGE_LineTo .PDFPAGE_Width, lngY + 25
.PDFPAGE_Stroke
'Schrift für die Liste festlegen
.PDFPAGE_SetActiveFont "Verdana", True, False, False, False, 14, 0
'Alle Datensätze durchlaufen
objRS.MoveFirst
Do While objRS.EOF = False
...
Loop
'Linie unter die Liste zeichnen
.PDFPAGE_SetLineWidth 1
.PDFPAGE_SetGrayStroke 0.5
.PDFPAGE_MoveTo 0, lngY - 2 + (14 * lngZeilenabstand)
.PDFPAGE_LineTo .PDFPAGE_Width, lngY - 2 + (14 * lngZeilenabstand)
.PDFPAGE_Stroke
'Dokument abschließen und speichern
.EndDoc
End With
End If
End Sub

Die Installation der Komponente erfolgt denkbar einfach mit Hilfe eines Setup-Programms. Dabei wird eine Datei Setup.ini innerhalb des Installationsverzeichnisses erstellt. Sie benötigen den dort enthaltenen Freischaltcode, um die Komponente in Ihrer Anwendung zu verwenden.

Sub ListeAusgeben()
...
'PDF-Datei erstellen
If objRS.RecordCount > 0 Then
With objPDF
'PDF-Datei erzeugen
'Initialisieren
.StartEngine "demo@demo", "demo"
'PDF-Datei im Anschluss öffnen
.AutoLaunch = True
'Dateiname festlegen
.FileName = strName
'Dokument erstellen
.BeginDoc
On Error GoTo FEHLER
...
.PDFPAGE_Stroke
FEHLER:
On Error Resume Next
'Dokument abschließen und speichern
.EndDoc
End With
End If
End Sub

Vorbereitungen

Zunächst müssen Sie innerhalb Ihres VBA-Projekts einen Verweis auf die Komponente einrichten. Sie wird im Dialogfeld Verweise als Amyuni PDFCreactiveX-Component aufgeführt.

Innerhalb des Codes, der in Listing 6 abgebildet ist, besteht der wesentliche Teil darin, den Freischalt- und Lizenzcode zu definieren. Am besten definieren Sie dazu zwei Konstanten auf Modulebene. Als Werte für die beiden Konstanten geben Sie als Lizenz den Wert Licensee aus der INI-Datei an und als Aktivierungscode den Wert LicCode der INI-Datei. Im folgenden Listings wurde nur ein Teil des Lizenzcodes angegeben.

Const Lizenz As String = "Suite Evaluation Developer"
Const Aktivierungscode As String = "07EFCDAB....276FD648F3"
Dim strPfad As String

Bevor Sie nun ein PDF-Dokument erstellen oder öffnen, müssen Sie die Methode SetLicence- Key aufrufen und ihr die Lizenz und den Aktivierungscode der Komponenten übergeben, die Sie auch mit der Anwendung ausliefern.

Programm-Info

Name: PDF-Creator
Hersteller: Amyuni Technologies (http://www.amyuni.com)
Preis: Developer-Version ab 800 US-$, kostenlose Testversion verfügbar
PDF-Erzeugung „on the fly“ mit VBA, VB etc., PDF-Viewer und grafischer Editor, auch für die manuelle PDF-Erstellung. Eine Datenbankanbindung ist möglich, sodass komfortabel Datenbankinhalte in die PDF-Dateien übernommen werden können.

PDF-Dateien erzeugen

Das Objektmodell der Komponente ist recht komplex. In aller Regel sollten Sie damit beginnen eine leere PDF-Datei zu öffnen, die Sie dann als Vorlage verwenden können. Als Pfad wird die Variable strPfad verwendet, die zuvor mit dem Datenbankpfad initialisiert wurde. Mit der AddPage-Methode können Sie dann eine Seite hinzufügen. Der numerische Parameter bestimmt die Seitenzahl der Seite und damit deren Position. Da die geöffnete PDF-Datei hier eine Seite enthält, wird mit AddPage (2) die zweite Seite ergänzt. Dies kann allerdings entfallen, wenn Ihre leere PDF-Datei schon eine leere Seite enthält.

Bild 3: Die PDFDatei mit grau unterlegten Zeilen.

Möchten Sie Text oder andere Objekte wie Bilder hinzufügen, verwenden Sie dazu die Create- Object-Methode der Komponente. Sie gibt allerdings nicht das erzeugte Objekt zurück, was am Anfang etwas gewöhnungsbedürftig ist. Mit dem ersten Parameter legen Sie den Objekttyp fest,mit dem zweiten den Namen. Den benötigen Sie, um anschließend mit der GetObjectByName- Methode das erzeugte Objekt zurückzugeben. Alle Eigenschaften wie Position und Formatierungen des Objekts bestimmen Sie über die Attribute-Auflistung. Mit der Save-Methode können Sie dann die Datei erstellen. Listing 7 zeigt, wie Sie auf diese Weise eine einfache Zeichenkette oben auf der ersten Seite ausgeben.

Bild 4: Die fertige Liste.

Sub PDFAusgabe()
Dim objPDF As ACPDFCREACTIVEX.PDFCreactiveX
Dim objDoc As ACPDFCREACTIVEX.acObject
Dim objText As ACPDFCREACTIVEX.acObject
Set objPDF = New ACPDFCREACTIVEX.PDFCreactiveX
strPfad = getDBPfad()
With objPDF
.SetLicenseKey Lizenz, Aktivierungscode
.Open strPfad & "leer.pdf", ""
'.AddPage (2)
'Text hinzufügen
.CreateObject acObjectTypeText, "MeinText"
'Text zurückgeben
Set objText = .GetObjectByName("MeinText")
'Textbox positionieren und formatieren
With objText
.Attribute("Left") = 200
.Attribute("Top") = 600
.Attribute("Right") = objPDF.PageWidth
.Attribute("Bottom") = 800
'Text formatieren
.Attribute("Text") = "Das ist der Inhalt des Textelelements"
.Attribute("TextFont") = "Verdana,11,700,1,0"
.Attribute("HorzAlign") = 2 'the text is centered
End With
'Datei speichern
.Save strPfad & "NeueDatei.pdf", 0
End With
Set objPDF = Nothing
End Sub

Eine Liste ausgeben

Das nachfolgende Beispiel soll auch für diese Komponente kurz zeigen, wie Sie eine Datensatzgruppe als Liste ausgeben. Auch hier sollen die einzelnen Zeilen abwechselnd grau und weiß unterlegt werden.

Da das Objektmodell dieser Komponente es erlaubt, auch für die Textboxen Hintergrundfarben festzulegen, ist der Code dazu wesentlich einfacher. Auch hier rufen Sie die Datensatzgruppe aus der Datenbank ab. Enthält die Gruppe Datensätze, durchlaufen Sie sie in einer Do-Loop-Schleife und innerhalb dieser die Felder in einer For-Each-Schleife. Für jedes Feld geben Sie dann eine Textbox aus und legen deren Positionen analog zum vorherigen Beispiel fest. Über die Attribute-Auflistung und den Index Back- Color kann dann abhängig von der aktuellen Zeilennummer die passende Hintergrundfarbe als RGB-Farbwert festgelegt werden.

Bild 5: Die mit dem Amyuni-PDF-Creator erzeugte Liste.

Sub ListeAusgeben()
Dim strSQL As String
Dim objRS As ADODB.Recordset
Dim objPDF As ACPDFCREACTIVEX.PDFCreactiveX
Dim objDoc As ACPDFCREACTIVEX.acObject
Dim objText As ACPDFCREACTIVEX.acObject
Set objPDF = New ACPDFCREACTIVEX.PDFCreactiveX
strPfad = getDBPfad()
Set objRS = New ADODB.Recordset
Dim lngX As Long
Dim lngY As Long
Dim objFeld As ADODB.Field
Dim lngZeile As Long
lngZeile = 0
Const lngZeilenabstand = 2
lngX = 10
lngY = 10
strName = getDBPfad() & "AmPDFCreatorListe.pdf"
strSQL = "SELECT * FROM Daten"
'SQL-Anweisung ausführen
objRS.Open strSQL, Application.CurrentProject.Connection, adOpenStatic
'PDF-Datei erstellen
If objRS.RecordCount > 0 Then
'PDF-Dokument öffnen
objPDF.SetLicenseKey Lizenz, Aktivierungscode
objPDF.Open strPfad & "leer.pdf", ""
'.AddPage (2)
'Text hinzufügen
objPDF.CreateObject acObjectTypeText, "MeinText"
'Text zurückgeben
Set objText = objPDF.GetObjectByName("MeinText")
'Textbox positionieren und formatieren
lngX = 0
lngY = 600
With objText
.Attribute("Left") = lngX
.Attribute("Top") = lngY
.Attribute("Right") = objPDF.PageWidth
.Attribute("Bottom") = lngY + 200
'Text formatieren
.Attribute("Text") = "DATEN"
.Attribute("TextFont") = "Verdana,20,700,0,0"
.Attribute("HorzAlign") = 2 'Zentriert
End With
'Datensätze durchlaufen
objRS.MoveFirst
lngX = 100
lngY = 1600
Do While Not (objRS.EOF)
lngZeile = lngZeile + 1
For Each objFeld In objRS.Fields
objPDF.CreateObject acObjectTypeText, "Feldwert"
'Text zurückgeben
Set objText = objPDF.GetObjectByName("Feldwert")
'Text positionieren und formatieren
With objText
.Attribute("Left") = lngX
.Attribute("Top") = lngY
.Attribute("Right") = objPDF.PageWidth - 100
.Attribute("Bottom") = lngY + 350
.Attribute("Text") = objFeld.Value
.Attribute("TextFont") = "Verdana,12,700,0,0"
.Attribute("HorzAlign") = 0 'linksbündig
If (lngZeile Mod 2) Then
.Attribute("BackColor") = RGB(230, 230, 230)
Else
.Attribute("BackColor") = RGB(255, 255, 255)
End If
End With
lngX = lngX + (objPDF.PageWidth / (objRS.Fields.Count) - 100)
Next
objRS.MoveNext
lngX = 100
lngY = lngY + 350
Loop
objRS.Close
'PDF-Dokument speichern und schließen
objPDF.Save strPfad & "AmuPDFListe.pdf", 0
End If
Set objPDF = Nothing
End Sub

Zusammenfassung

Beide Komponenten sind einfach einzusetzen, weisen jedoch Besonderheiten im Objektmodell auf, die etwas von dem abweichen, was die meisten VBA-Programmierer kennen. Hat man sich jedoch einmal an die Eigenheiten gewöhnt, ist die PDF-Erzeugung mit beiden Komponenten recht unkompliziert.

Aus Entwicklersicht ist die Dokumentation des Amyuni-PDFCreators jedoch nicht ganz optimal, da sie sich vorrangig auf die Arbeit mit den mitgelieferten Tools bezieht, aber nicht so sehr auf das Objektmodell eingeht. Der PDF Creator Pilot von Two Pilots liefert hingegen eine ausreichende Dokumentation des Objektmodells mit.

Komponenten und Anbieter im Überblick