Excel als Report-Generator - Teil 2

15.07.2006 von Michael W.  Welling
Listen direkt nach Excel exportieren, dort weiterverarbeiten oder ausdrucken: Mit dem Export-Generator schlägt man zwei Fliegen mit einer Klappe, denn er bietet zum einen die oft geforderte Exportfunktion und zum anderen anpassbare Listen zum Versenden und Ausdrucken.

Wie bereits im ersten Teil des Artikels erwähnt,sind komplexe Berichte mit Unterberichten und Gruppierung sehr aufwendig. Es wäre zwar grundsätzlich möglich, aber wir wollen das Rad nicht neu erfinden. Und der Report-Generator von Access ist, nebenbei gesagt, sehr leistungsfähig. Und das nicht nur alleine durch die schier unbegrenzten Möglichkeiten bei der Nutzung von VBA.

Trotzdem gibt es Berichte, die ein gewisses Maß an Flexibilität aufweisen müssen, zum Beispiel Referenzlisten oder auch Preislisten. Nicht jeder darf alles wissen, was auf so einem vordefinierten Bericht steht. Und lange nicht jeder ist froh, wenn er durch dicke schwarze Balken an diesen Umstand erinnert wird. Natürlich kann man für jeden denkbaren Anwendungsfall Berichte in Access erstellen. Man kann diese Arbeit aber auch dem Endanwender überlassen. Er will es in der Regel sowieso anders, als Sie es sich vorgestellt haben.

Das bisherige Konzept erweitern

Mit einem erweiterten Bericht ist der Druck mehrer Datensätze als Liste gemeint (Bild 1).

Bild 1: Erweiterter Bericht am Beispiel einer Artikelliste.
Bild 2: Erweiterung der Tabelle zur Felddefinition um die Spalten Direction und RangeName.

In Bild 3 sieht man rot umrandet die Erweiterung der Tabelle USys_FUR_Field mit Details zum Feldbeziehungsweise dessen Inhalt und der Stelle in Excel, an die es gesetzt wird. Das dazugehörige Profil wird in Bild 4 angelegt. Es handelt sich um die Felder Direction und RangeName. In die Spalte Direction wird eingegeben, in welche Richtung eine Liste nach dem ersten Datensatz fortgesetzt wird. In der Regel ist das zwar nach unten, aber es werden Ihnen bestimmtnoch andere Anwendungsgebiete einfallen, wo eine Liste nach rechts fortgesetzt werden muss. Die in diesem Beispiel verwendeten Eingaben für das Feld Direction können lauten Oben, Unten, Rechts, Links

Bild 3: Durch Anfügen eines weiteren Profils wird der Druck einer benutzerdefinierten Artikelliste möglich.
Bild 4: Definition von Namen für Zellen und Bereiche in einer Excel-Datei.

Durch geschickte Formatierung mit Zeilenumbrüchen bietet Excel sogar den Komfort, Zeilen mit dynamischer Höhe zu erhalten (Bild 1)

Jetzt wird’s interessant

Vielleicht ist Ihnen schon die neue Spalte RangeName ins Auge gesprungen. Bei der bis jetzt vorherrschenden Lösung muss der imaginäre Kunde auf jeden Fall an zwei Stellen Änderungendurchführen, wenn er sein Berichtslayout ändern will: im Excel-Bericht und in der Metadaten-Tabelle USys_FUR_Field, um dem System eventuelle Änderungen der Zielzelle mitzuteilen. Mit einem kleinen Trick lässt sich das für viele Anwendungsfälle umgehen. Dazu nutzt man einfach die Namen, die man in Excel einer Zelle oder einem Bereich zuordnen kann. Man teilt dem Benutzer einfach mit, welche Namen er in seiner Excel-Datei verwenden darf, und die Anwendung exportiert die Daten dann andiese Stelle in der Excel-Datei. Damit wird das Layouten noch benutzerfreundlicher. Den erweiterten Code der Funktion FUR_PrintOut finden Sie im Listing 1.

Public _
Function FUR_PrintOut( _
ByVal DataSource As DAO.Recordset, _
ByVal ProfileKey As String, _
Optional ByVal PrintDirectly As Boolean = False) As Long
On Error GoTo RunError
Dim sql As String

(Code aus Listing des ersten Teils der Artikelfolge)

'**********************************************************
'* Worksheet-Objekt-Variable definieren
Dim exc_wks As Object
'*******************************************************
'* Daten aus Tabelle in Report übertragen
Dim Sheet As String
Dim Row As Long
Dim col As Long
'* Zähler definieren (Datensatz-Zähler)
Dim Counter As Long
Counter = 0
'* Export des Datums möglich?
Dim flg_Export As Boolean
'* Für jeden Datensatz durchschleifen, ...
DataSource.MoveFirst
While Not DataSource.EOF
'* Für jedes Feld in Metadaten durchschleifen, ...
mta.MoveFirst
While Not mta.EOF
'* Grundsätzlich 'Ja'
flg_Export = True
'* Feld-Name ermitteln
Dim FieldName As String
FieldName = mta!((FieldName))
'* eventuell definierten Namen ermitteln
Dim RName As String
RName = mta!((RangeName)) & ""
'* Zeile und Spalte müssen angegeben sein, ...
If RName <> "" Then
'* Den Zellbezug dieses Namens ermitteln
Dim dmy As String
dmy = exc_wkb.Names.Item(RName).RefersTo
'* Trennzeichen "!" in der Referenz-Angabe
'* ermitteln (entspricht dem Arbeitsblatt)
pos = InStr(1, dmy, "!")
'* Arb.-blatt (bis Trennzeichen) ermitteln
Sheet = Left(dmy, pos - 1)
Sheet = Right(Sheet, Len(Sheet) - 1)
'* Arb.-blatt im Excel-Sheet referenzieren
Set exc_wks = exc_wkb.Worksheets(Sheet)
'* Rangename (ab Trennzeichen) ermitteln
Dim Rng As String
Rng = Right(dmy, Len(dmy) - pos)
'* Zeile und Spalte der Range ermitteln
Row = exc_wks.Range(Rng).Cells(1, 1).Row
col = exc_wks.Range(Rng).Cells(1, 1).Column
flg_Export = True
Else
'* Wurden Angaben für Zelle gemacht?, ...
If (mta!((Row)) & "" = "") Or _
(mta!((Column)) & "" = "") Then
'* Export nicht möglich (zu wenig Angaben)
flg_Export = False
Else
'* Zeile ermitteln
Row = mta!((Row))
'* Spalte ermitteln
col = mta!((Column))
'* Arbeitsblatt ermitteln
Sheet = mta!((Worksheet)) & ""
'* Seite im Excel-Sheet referenzieren
Set exc_wks = exc_wkb.Worksheets(Sheet)
End If
End If
'* Wenn Export möglich ist, ...
If flg_Export = True Then
'* bei mehr als einem Datensatz,
'* relative Positionen von Zeilen
'* und Spalten ermitteln
Select Case mta!((Direction))
Case "oben"
Row = Row - Counter
Case "unten"
Row = Row + Counter
Case "rechts"
col = col - Counter
Case "links"
col = col + Counter
End Select
'* Datum in Zelle einfügen
exc_wks.Cells(Row, col).Value = _
DataSource(FieldName)
End If
'* nächstes Feld
mta.MoveNext
Wend
'* Zähler erhöhen
Counter = Counter + 1
'* nächsten Datensatz
DataSource.MoveNext
Wend

((Code aus Listing des ersten Teils der Artikelfolge))
...

Im Listing 2 wird dargestellt, wie man die Funktion FUR_PrintOut verwendet, um den Listendruck durchzuführen.

FUR_ PrintOut zum Ausdruck einer Liste
Public _
Function PrintArtikelliste( _
Optional ByVal PrintDirectly As Boolean = False) _
As Long
On Error GoTo RunError
'* Auswahl-Abfrage generieren
Dim sql As String
sql = ""
sql = sql & "SELECT"
sql = sql & " *"
sql = sql & " FROM"
sql = sql & " [tbl_Artikel]"
Dim dbs As DAO.Database
Set dbs = CurrentDb()
Dim rst As DAO.Recordset
Set rst = dbs.OpenRecordset(sql, dbOpenSnapshot)
'* Bericht drucken, Profil "al" anwenden
Dim rtn As Long
rtn = FUR_PrintOut(rst, "al", PrintDirectly)
rst.Close
dbs.Close
RunError:
Select Case Err.Number
Case 0
Case Else
MsgBox Err.Description, _
vbCritical, _
"Nr. " & Err.Number
End Select
RunTerminate:
Set rst = Nothing
Set dbs = Nothing
End Function