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.
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"
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.
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).
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.
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.
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