Monatskalender als Bericht drucken

Mit Access-Bericht lässt sich eine Menge anstellen, was allerdings einiges an Erfahrung und übung erfordert. Ein Monatskalender, der Datumsangaben in einem Raster von Wochen und Wochentagen enthält, ist erstens eine recht interessante Aufgabe und zweitens macht er sich auf verschiedenen Dokumenten gut: Haben Sie schon einmal überlegt, einem Kunden eine Monatsübersicht zu dem Tag mitzuliefern, an dem ein Ereignis wie zum Beispiel eine Bestellung erfolgt

Tage mal Wochen

Ein Monatskalender ist üblicherweise in ein Raster eingeteilt, das oben die Kalendertage (Montag, Dienstag …), links die Kalenderwochen und in der aufgespannten Tabelle die Tagesdaten enthält. Anschaulich zeigt dies Abb. 1.

pic001.tif

Bild 1: Ein Monatskalender als Bericht

Datenherkunft eines Kalenderberichts

Es gibt prinzipiell zwei Möglichkeiten, einen Kalender wie in Bild 1 zu erstellen: Die erste beruht darauf, eine Reihe von Steuerelementen in der gezeigten Anordnung zu platzieren und diese zur Laufzeit mit den gewünschten Werten zu füllen. Da aber keiner Lust hat, mehr als 50 Steuerelemente in den Berichtsentwurf einzufügen, stellen wir hier eine etwas elegantere Lösung vor, die außerdem wesentlich datenbankbezogener ist: Dazu benötigen Sie zunächst eine Tabelle mit Kalenderdaten. Diese sieht im Entwurf wie in Bild 2 aus und wird mit der Routine aus Listing 1 gefüllt. Mit dem Aufruf dieser Routine übergeben Sie das Start- und das Enddatum der anzulegenden Datumsdatensätze. Der Aufruf zum Anlegen aller Kalenderdaten des Jahres 2007 sieht etwa so aus:

Listing 2: Snapshot-Datei ohne visuelles Snapshot Viewer Control ausdrucken

Public Sub KalendertabelleFuellen(dateStartdatum As Date, dateEnddatum As Date)
     Dim dateAktuellesdatum As Date
     Dim db As DAO.Database
     Dim strDatum As String
     Set db = CurrentDb
     ''Alte Daten löschen
     db.Execute "DELETE FROM tblKalenderdaten", dbFailOnError
     ''Daten in einer Schleife eintragen
     For dateAktuellesdatum = dateStartdatum To dateEnddatum
         strDatum = SQLDatum(dateAktuellesdatum)
         db.Execute "INSERT INTO tblKalenderdaten(Kalenderdatum) VALUES(" _
& strDatum & ")", dbFailOnError Next dateAktuellesdatum End Sub KalendertabelleFuellen "1.1.2007", "31.12.2007"
pic002.tif

Bild 2: Entwurf einer Tabelle mit Kalenderdaten

Eins nach dem anderen

Damit Sie die Vorgehensweise leicht nachvollziehen können, beschreiben wir Schritt für Schritt, wie der Kalenderbericht entsteht.

Zunächst legen Sie einen Bericht an, weisen ihm als Datenherkunft die Tabelle tblKalenderdaten zu und speichern ihn unter dem Namen rptMonatsansichtKlein.

Fügen Sie das Feld Kalenderdatum zum Detailbereich hinzu und wechseln Sie zur Vorschauansicht: Es ergibt sich das Bild aus Bild 3. Der Bericht enthält nun zumindest schon einmal eine Reihe von Kalenderdaten.

pic003.tif

Bild 3: Bericht mit einer Auflistung von Kalenderdaten

Allerdings soll der Kalender ja nur die Tage anzeigen. Dazu fügen Sie ein Textfeld namens txtTag hinzu, entfernen sein Beschriftungsfeld und stellen seine Eigenschaft Steuerelementinhalt auf den folgenden Ausdruck ein:

=Day(Kalenderdatum)

Entfernen Sie außerdem das ursprüngliche Datumstextfeld Kalenderdatum. Der Bericht zeigt in der Vorschau nun immerhin schon einmal die Kalendertage an (siehe Bild 4).

pic004.tif

Bild 4: Statt der kompletten Daten zeigt der Bericht nun nur noch die Kalendertage an.

Nun wollen diese angeordnet werden – und zwar so, dass jeweils die Montage ganz links und jeweils die Tage einer Woche in einer Reihe stehen. Dazu setzen Sie die Eigenschaft MoveLayout ein, die [1] genauer erläutert.

Jedes angezeigte Datum soll auf den Wochentag geprüft und davon abhängig von links nach rechts positioniert werden. Die dafür notwendige Routine muss also für jeden Datensatz ausgelöst werden, was etwa mit der Ereigniseigenschaft Beim Formatieren des Detailbereichs möglich ist. Listing 2 zeigt eine Routine, die wie gewünscht vorgeht.

Listing 2: Aufteilen der Tageszahlen auf mehrere Reihen á sieben Spalten

Const cintBreite As Integer = 300 
Private Sub Detailbereich_Format(Cancel As Integer, FormatCount As Integer)
     ''Wenn Wochentag = Sonntag, dann...
     If Weekday(Me!Kalenderdatum) = 1 Then
         ''implizit: Me.MoveLayout = True, Ausgabe in nächster Zeile fortsetzen
         ''Steuerelement rechts anordnen
         Me!txtTag.Left = cintBreite * 7
         ''... sonst:
     Else
         ''nicht zur nächsten Zeile vorrücken
         Me.MoveLayout = False
         ''Steuerelemente passend anordnen
         Me!txtTag.Left = cintBreite * (Weekday(Me.Kalenderdatum) - 1)
     End If
End Sub

Diese Routine prüft, ob es sich bei dem Tag um einen Sonntag handelt, und legt den Abstand des Steuerelements vom linken Rand auf das Siebenfache des Werts der Konstanten cintBreite fest, die im gleichen Modul deklariert wird. Dadurch verschiebt die Routine alle Textfelder, deren Datum einen Sonntag enthält, relativ weit nach rechts.

In allen anderen Fällen, also bei den Wochentagen Montag bis Samstag, ermittelt die Routine den Abstand vom linken Rand über das Produkt aus dem Wert der Weekday-Funktion (die etwa für den Montag standardmäßig den Wert 2 liefert) und dem Wert der oben genannten Konstanten.Gleichzeitig stellt sie die Eigenschaft MoveLayout jeweils auf den Wert False ein, was dazu führt, dass der folgende Datensatz in die gleiche Zeile geschrieben wird. Im Bericht sieht das nun wie in Bild 5 aus.

pic005.tif

Bild 5: Kalendertage in Reih und Glied – allerdings noch reichlich viel für eine Monatsübersicht.

Daten eines Monats anzeigen

Nun enthält der Bericht noch alle Tage der Datenherkunft, allerdings soll er nur die Tage eines einzigen Monats anzeigen. Der Einfachheit halber soll dies standardmäßig der Monat zum aktuellen Tag sein, den Sie mit der VBA-Funktion Date ermitteln können; alternativ kann der Bericht das gewünschte Daten aus dem öffnungsargument (OpenArgs-Parameter, ab Access 2002) oder einer globalen Variablen entnehmen, die man natürlich vorher entsprechend füllen muss. Zu diesem Tag ermitteln Sie dann mit den in [2] vorgestellten Funktionen den ersten und den letzten Tag des Monats. [3] liefert die beiden Funktionen MontagErmitteln und SonntagErmitteln.

Diese brauchen Sie, um den ersten Montag der ersten und den letzten Sonntag der letzten Zeile zu ermitteln – auch wenn sie nicht zum aktuellen Monat gehören. Immerhin soll der Bericht wie in Bild 1 die erste und die letzte Zeile um die fehlenden Tage ergänzen und diese grau einfärben. Um die übersicht zu wahren, speichern Sie die Ergebnisse dieser Funktionen in den folgenden im Berichtsmodul deklarierten Variablen:

Dim dateErsterTagDesMonats As Date
Dim dateLetzterTagDesMonats As Date
Dim dateErsterKalendertag As Date
Dim dateLetzterKalendertag As Date

In einer weiteren Variablen speichern Sie das Referenzdatum – also bis dato das aktuelle Datum:

Dim dateReferenzdatum As Date

Die Datenherkunft soll nun auf die Daten des Monats (plus Vorläufer/Nachzügler), in dem der aktuelle Tag oder der per OpenArgs übergebene Tag liegt, eingeschränkt werden. Dies erledigen Sie in der Routine, die durch das Ereignis Beim öffnen des Berichts ausgelöst wird (s. Listing 3).

Listing 3: Ermitteln des angezeigten Zeitraums und filtern des Berichts

Private Sub Report_Open(Cancel As Integer)
     ''Prüfen, ob Datum übergeben wurde (ab Access 2002), 
     ''sonst aktuelles Datum als Referenzdatum verwenden
     If IsNull(Me.Properties!OpenArgs) Then
         dateReferenzdatum = Date
     Else
         dateReferenzdatum = Me.OpenArgs
     End If
     ''Ersten und letzten Tag des Monats ermitteln
     dateErsterTagDesMonats = MonatsbeginnErmitteln(dateReferenzdatum)
     dateLetzterTagDesMonats = MonatsendeErmitteln(dateReferenzdatum)
     ''Aus erstem und letztem Tag die ersten und letzten Tage der 
     ''jeweiligen Kalenderwochen ermitteln
     dateErsterKalendertag = MontagErmitteln(dateErsterTagDesMonats)
     dateLetzterKalendertag = SonntagErmitteln(dateLetzterTagDesMonats)
     ''Filter des Berichts auf die anzuzeigenden Tage einstellen und 
     ''aktivieren
     Me.Filter = "Kalenderdatum >= " & SQLDatum(dateErsterKalendertag) _
& " AND Kalenderdatum <= " & SQLDatum(dateLetzterKalendertag) Me.FilterOn = True End Sub

Die Routine prüft zunächst, ob der Aufruf ein öffnungsargument enthält, und verwendet dieses oder alternativ das aktuelle Datum als Referenzdatum. Dann füllt es die vier oben genannten Variablen dateErsterTagDesMonats, dateLetzterTagDesMonats, dateErsterKalendertag und dateLetzterKalendertag.

Anhand der letzten beiden dieser Variablen stellt die Routine dann ein Filterkriterium zusammen, weist es der Eigenschaft Filter des Berichts zu und aktiviert den Filter durch Setzen der Eigenschaft FilterOn auf den Wert True. Das Ergebnis ist die Berichtsvorschau in Bild 6.

pic006.tif

Bild 6: Die Kalendertage eines Monats inklusive einiger Tage des vorherigen Monats

Monatsansicht mit Beschriftungen und Linien versehen

Der größte Teil der Arbeit ist nun erledigt, nun folgen noch einige Schönheitsarbeiten. Da wäre zunächst der Kopfbereich des Berichts, der ein Textfeld namens txtMonat für die Anzeige des Monats sowie die Bezeichnung der Wochentage enthält.

Diese fügen Sie ganz einfach wie in Bild 7 hinzu. Gleichzeitig ergänzen Sie den Bericht um ein weiteres Textfeld namens txtKW im Detailbereich, das die Kalenderwoche anzeigen soll; dieses Textfeld bleibt zunächst ungebunden.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar