Die grafische Umsetzung von Zeit- und Projektplänen gehört leider nicht zur Standard- Ausstattung von Access. Zwar lassen sich viele Diagrammvarianten für unterschiedlichste Aufgaben einsetzen, aber wenn Sie eine Projekt- oder Urlaubs-Planung als Zeitlinie in einem Bericht ausgeben wollen, findet sich keine passende Lösung. Mithilfe der Standard-Steuerelemente, und zwar insbesondere des Rechtecks aus der Zeichenfunktion, lässt sich Access aber leicht austricksen.
So funktioniert die Lösung
Dem Bericht liegen zwei einfache Tabellen zugrunde: „Projekte“ und „Projektdetails“. „Projekte beinhaltet lediglich ein Feld „ProjektName“ und dient zur Verknüpfung von einzelnen Tätigkeiten mit einem Projekt. In „Projektdetails“ finden sich diese Tätigkeiten zusammen mit einem Start- und einem Abschluss-Datum. Diese Daten sollen pro Projekt als Zeitlinien in einem Bericht ausgegeben werden. Dazu erfolgt im Bericht eine Gruppierung nach „Projektname“. Im Detailbereich sind dann die einzelnen Tätigkeiten sortiert nach Start-Datum aufgeführt.
Wichtig ist, dass für den Gruppenkopf „ProjektName“ die Eigenschaft „Neue Seite“ auf „Vor Bereich“ eingestellt ist – in der Ereignisprozedur „Beim Formatieren“ des Gruppenkopfes werden pro Projekt wichtige Basisdaten berechnet, ohne die im Detailbereich keine korrekte Darstellung erfolgen kann:
Listing 1
Set db = CurrentDb()
strSQL = „select Min([StartDatum]) as tmpStartDatum from Projektdetails where [ProjektName]= ‚“ & Me.ProjektName & „‚;“
Set rs = db.OpenRecordset(strSQL, dbOpenSnapshot)
If rs.RecordCount > 0 Then datVonDatum = rs(„tmpStartDatum“)
strSQL = „select Max(IIf(IsDate([AbschlussDatum]),CDate([AbschlussDatum]),Null)) as tmpAbschlDatum from Projektdetails where [ProjektName]= ‚“ & Me.ProjektName & „‚“
Set rs = db.OpenRecordset(strSQL, dbOpenSnapshot)
If rs.RecordCount > 0 Then datBisDatum = rs(„tmpAbschlDatum“)
rs.Close
intTagesDifferenz = DateDiff(„d“, datVonDatum, datBisDatum)
Im ersten Schritt ermitteln wir hier das erste und das letzte Datum der verschiedenen Tätigkeiten des jeweiligen Projektes, um daraus die Anzahl Tage als Anhaltspunkt für einen pro Tätigkeit anzuzeigenden Balken zu errechnen. Diese Werte halten wir in den globalen Variablen „datVonDatum“, „datBisDatum“ und „intTagesDifferenz“ für spätere, im Detailbereich stattfindende Berechnungen fest.
Me.lblZeitlinieGesamt.Caption = CStr(intTagesDifferenz) & “ Tage“
Me.txtVonDatum.Caption = Format(datVonDatum, „dd.mm.yyyy“)
Me.txtBisDatum.Caption = Format(datBisDatum, „dd.mm.yyyy“)
Anschließend setzt die Prozedur verschiedene Bezeichnungsfelder für die Anzeige des ersten und des letzten Tätigkeitsdatums sowie der Anzahl der Tage insgesamt.
Me.ScaleMode = 1 ‚Einheit= „Twips“…
sngFaktor = Me.recGanzesProjekt.Width / intTagesDifferenz
intOfs = Me.recGanzesProjekt.Left
End Sub
Zum Schluss errechnet die Prozedur einen Faktor für die Skalierung eines pro Tätigkeit anzuzeigenden Balkens, basierend auf der Anzahl ermittelter Lauftage für das Projekt. Das Rechteck „recGanzes- Projekt“ stellt einen Zeitbalken im Gruppenkopf dar, an dem später die darunter befindlichen Balken der einzelnen Tätigkeiten von links nach rechts ausgerichtet werden. Die globale Variable „intOfs“ hält dazu den linken Rand des „Hauptbalkens“ fest, von dem aus gerechnet die Balken pro Tätigkeit abhängig von ihrem Starttag positioniert werden.
Die eigentliche Berechnung der Balken pro Tätigkeit sowie deren Beschriftung erfolgt in der Ereignisprozedur „Beim Formatieren“ im Detailbereich. Der Balken pro Tätigkeit wird nur angezeigt, wenn sowohl ein Start- als auch ein Abschlussdatum vorhanden sind:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Dim intErsterTag As Integer, intTageTätigkeit As Integer
If Not IsNull(Me.StartDatum) And Not IsNull(Me.AbschlussDatum) Then
intErsterTag = DateDiff(„d“, datVonDatum, Me.StartDatum) + 1
intTageTätigkeit = DateDiff(„d“, Me.StartDatum, Me.AbschlussDatum) + 1
If intErsterTag <= 0 Then intErsterTag = 1
Hier ermitteln wir zunächst den ersten Tag der einzelnen Tätigkeit und damit die linke Position, an der der Balken unter dem „Hauptbalken“ zu positionieren ist. Dann ermitteln wir die Dauer dieser Tätigkeit in Tagen für die Länge des Balkens.
Me.recBalken.Width = 1
Me.recBalken.Left = intOfs + ((intErsterTag – 1) * sngFaktor)
On Error Resume Next
Me.recBalken.Width = ((intTageTätigkeit – 1) * sngFaktor)
If Err Then Me.recBalken.Width = 20
Hier erfolgt die Einstellung für die linke Position und die Länge der einzelnen Balken. Access meldet einen Laufzeitfehler, wenn das für die Darstellung verwendete Rechteck „recBalken“ zu breit für den Detailbereich ist.
Deswegen setzen wir die Breite zunächst auf „1“, positionieren dann links entsprechend des ersten Tages der Tätigkeit unter dem „Hauptbalken“ und setzen erst dann die Breite gemäß der Dauer der Tätigkeit. Kommt es dabei zu einem Fehler, wird die Breite des Balkens kurzerhand auf „20“ gesetzt, um zumindest eine farbliche Hervorhebung zu gewährleisten.
Me.lblTageGesamt.Left = Me.recBalken.Left
Me.lblTageGesamt.Caption = CStr(intTageTätigkeit) + “ Tag(e)“
Me.recBalken.Visible = True
Me.lblTageGesamt.Visible = True
Abschließend setzen wir das Bezeichnungsfeld „lblTageGesamt“ auf die Dauer der jeweiligen Tätigkeit, positionieren es über dem Balken und zeigen dann Balken und Bezeichnungsfeld an.
Else
Me.recBalken.Visible = False
Me.lblTageGesamt.Visible = False
End If
End Sub
Wenn weder Start- noch Abschluss-Datum gelesen werden konnten, also eine Tätigkeit noch nicht komplett erfasst ist, blenden wir im Else-Zweig Balken und Bezeichnungsfeld aus.
Nutzen Sie das Zeitplan-Diagramm in Ihren Datenbanken
Um die Lösung in eigenen Datenbanken einzusetzen, muss eine Gruppierung nach dem Projektnamen möglich und pro Tätigkeit oder Aktivität ein Start- und ein Abschluss-Datum vorhanden sein.
Die Lösung benötigt also die Felder „ProjektName“, „Tätigkeit“, „StartDatum“ und „AbschlussDatum“, die Sie aus vorhandenen Daten recht einfach über eine Abfrage zur Verfügung stellen können.
Wenn dort das Feld mit dem Projektnamen beispielsweise „ProjektBezeichnung“ heißt, geben Sie in der Abfrage zum Beispiel „ProjektName: ProjektBezeichnung“ ein und generieren so quasi ein „Feldmapping“ für den Bericht.
Zum Beispiel: In Ihrer Datenbank tragen die Tabellen die Namen „ProjektBasis“ und „ProjektAktivitäten“ und beinhalten die Felder „ProjektBezeichnung“, „Aktivität“, „DatumStart“ und „DatumEnde“.
In der Abfrage nehmen Sie ein Mapping wie unten gezeigt vor und weisen diese Abfrage dem Bericht „Projektübersicht“ zu. Dabei können Sie selbstverständlich weitere Felder wie beispielsweise „Projektleiter“ oder „Kostenstelle“ aufnehmen und diese im Gruppenkopf oder Detailbereich des Berichtes nach Belieben hinzufügen.
Die gesamten Programmierungen:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Dim intErsterTag As Integer, intTageTätigkeit As Integer
If Not IsNull(Me.StartDatum) And Not IsNull(Me.AbschlussDatum) Then
intErsterTag = DateDiff(„d“, datVonDatum, Me.StartDatum) + 1
intTageTätigkeit = DateDiff(„d“, Me.StartDatum, Me.AbschlussDatum) + 1
If intErsterTag <= 0 Then intErsterTag = 1
Me.recBalken.Width = 1
Me.recBalken.Left = intOfs + ((intErsterTag – 1) * sngFaktor)
On Error Resume Next
Me.recBalken.Width = ((intTageTätigkeit – 1) * sngFaktor)
If Err Then Me.recBalken.Width = (Me.Left + Me.Width) – Me.recBalken.Left
Me.lblTageGesamt.Left = Me.recBalken.Left
Me.lblTageGesamt.Caption = CStr(intTageTätigkeit) + “ Tag(e)“
Me.recBalken.Visible = True
Me.lblTageGesamt.Visible = True
Else
Me.recBalken.Visible = False
Me.lblTageGesamt.Visible = False
End If
End Sub
Private Sub Gruppenkopf0_Format(Cancel As Integer, FormatCount As Integer)
Dim db As Database, rs As Recordset, strSQL As String
Set db = CurrentDb()
strSQL = „select Min([StartDatum]) as tmpStartDatum from Projektdetails where [ProjektName]= ‚“ & Me.ProjektName & „‚;“
Set rs = db.OpenRecordset(strSQL, dbOpenSnapshot)
If rs.RecordCount > 0 Then datVonDatum = rs(„tmpStartDatum“)
strSQL = „select Max(IIf(IsDate([AbschlussDatum]),CDate([AbschlussDatum]),Null)) as tmpAbschlDatum from Projektdetails where [ProjektName]= ‚“ & Me.ProjektName & „‚“
Set rs = db.OpenRecordset(strSQL, dbOpenSnapshot)
If rs.RecordCount > 0 Then datBisDatum = rs(„tmpAbschlDatum“)
rs.Close
intTagesDifferenz = DateDiff(„d“, datVonDatum, datBisDatum)
Me.lblZeitlinieGesamt.Caption = CStr(intTagesDifferenz) & “ Tage“
Me.txtVonDatum.Caption = Format(datVonDatum, „dd.mm.yyyy“)
Me.txtBisDatum.Caption = Format(datBisDatum, „dd.mm.yyyy“)
Me.ScaleMode = 1 ‚Einheit= „Twips“…
sngFaktor = Me.recGanzesProjekt.Width / intTagesDifferenz
intOfs = Me.recGanzesProjekt.Left
End Sub