Bericht als Snapshot speichern

Oftmals ist es notwendig, ein Bericht aus Access als Snapshot an einem bestimmten Ort zu speichern.
Die Programmierung lautet:

Dim strPath As String
Const conBerichtName = „Artikel nach Kategorie“

strPath = „c:\a\Test.snp“
SnapOutputSend conAlsDatei, conBerichtName, strPath

Diese Programmierung können sie zum Beispiel auf einer Schaltfläche (Visual Basic) kopieren. Ändern Sie nur die Konstanten.


conBerichtName ist Der Berichtsname, der als Snapshot-Datei exportiert werden soll.
strPath ist der Pfad und Dateiname, wohin und unter welchen Namen die Snaphot-Datei gespeichert werden soll.

Sie benötigen noch ein Modul.
Erstellen Sie ein Modul mit dem Namen modSnapshot. Kopieren Sie die Programmierung einfach in das Modul.

modSnapshot (Bericht als Snapshot speichern)

Option Compare Database
Option Explicit

Public Const conAlsDatei As Integer = 0, conViaEMail As Integer = 1

Sub SnapOutputSend(intModus As Integer, _
strBerichtName As String, _
strPathOrEmail As String)

Dim strBetreff As String

Const conText = „Anbei wie besprochen der Bericht…“
Const conFormat = „Snapshot Format“

DoCmd.Hourglass True

strBetreff = „Bericht “ & strBerichtName

Select Case intModus

Case conAlsDatei
If Len(strPathOrEmail) > 0 Then
DoCmd.OutputTo acOutputReport, strBerichtName, conFormat, strPathOrEmail
DoEvents
Else
DoCmd.Hourglass False
Beep
MsgBox „Ausgabe in Datei nicht möglich, Pfad nicht angegeben!“, vbOKOnly + vbCritical, „!!! Fehler !!!“
Exit Sub
End If

Case conViaEMail
If Len(strPathOrEmail) > 0 Then
On Error Resume Next
DoCmd.SendObject acSendReport, strBerichtName, conFormat, strPathOrEmail, , , strBetreff, conText, False
DoEvents
If Err <> 0 Then
Beep
MsgBox „Versand via EMail nicht möglich, es ist ein Fehler aufgetreten!“, vbOKOnly + vbCritical, „!!! Fehler !!!“
End If
Else
DoCmd.Hourglass False
Beep
MsgBox „Versand via EMail nicht möglich, Empfänger nicht angegeben!“, vbOKOnly + vbCritical, „!!! Fehler !!!“
Exit Sub
End If

Case Else
Beep
MsgBox „OutputSend: Modus nicht angegeben!“, vbOKOnly + vbCritical, „!!! Fehler !!!“

End Select

DoEvents
DoCmd.Hourglass False

End Sub

Function AddSlash$(aPath$)

AddSlash = aPath
If Trim$(aPath) = „“ Then Exit Function
If Right$(aPath, 1) = „\“ Then Exit Function
AddSlash = aPath + „\“

End Function
Function PathOnly$(aPath$)
Dim L%

PathOnly = „“
If InStr(aPath$, „\“) = 0 Then Exit Function
L = Len(aPath$)
While Mid$(aPath$, L, 1) <> „\“ And L > 0
L = L – 1
Wend
If L > 1 Then PathOnly = Left$(aPath$, L)
End Function
Function GetDataBasePath() As String
Dim db As Database, L%, aPath$

Set db = CurrentDb()
aPath$ = db.Name
L = Len(aPath$)
While Mid$(aPath$, L, 1) <> „\“ And L > 0
L = L – 1
Wend
If L > 1 Then
aPath$ = Left$(aPath$, L)
Else
aPath$ = „“
End If
GetDataBasePath = aPath$

End Function

Berichtausgabe bremst Rechner aus

Frage:

Ich habe einen umfangreichen Bericht mit mehreren Unterberichten, die zum Teil auf eigenen Abfragen basieren. Dass das Öffnen des Berichtes etwas länger dauert, ist mir verständlich. Allerdings geht dabei die CPU-Auslastung gegen 100 % und in der Titelleiste von Access wird „(Keine Rückmeldung)“ angezeigt.

Woran kann das liegen und wie lässt sich das Problem beseitigen?

Antwort:

Vermutlich setzen Sie im Bericht oder in den Abfragen Felder ein, in denen Formeln wie z.B. „=[txtNetto] + [txtMwst]“ enthalten sind oder aus denen Sie globale Funktionen aufrufen. Das kann dazu führen, dass während des Öffnens des Berichtes das System fast vollständig ausgelastet wird. Ursache dafür ist Access, das während des Aufbaus des Berichtes, der Berechnung von Formeln und der Ausführung von Funktionen keine CPU-Zeit freigibt, damit das Ergebnis schnellstmöglich zur Verfügung gestellt werden kann.

Sie können diese Systembeeinträchtigungen wie folgt verringern:

  1. Öffnen Sie zunächst den Bericht, der Textfelder mit Formeln enthält, im Entwurfsmodus.
  2. In der Ereignisprozedur „Beim Drucken“ des Detailbereiches fügen Sie die folgende Anweisung ein:

    Private Sub Detail1_Print (Cancel As Integer, PrintCount As Integer)
    DoEvents
    End Sub

Auf diese Weise wird zunächst bei jedem Datensatz und somit auch nach jeder Berechnung einer Formel die Abgabe von CPU-Zeit erzwungen.

Enthält bereits die dem Bericht zugrunde liegende Abfrage Formeln oder Funktionsaufrufe, lässt sich die Abgabe von CPU-Zeit über eine kleine VBA-Routine erzwingen:

  1. Kopieren Sie zunächst die folgende Funktion in ein beliebiges Modul:

    Function CPUZeitFreigeben()
    DoEvents
    End Function
  2. In der Abfrage geben Sie dann in einer leeren Spalte die Formel „X: CPU Zeit- Freigeben()“ in die Zeile „Feld“ ein. Bei jedem ausgewerteten Datensatz wird nun diese Funktion aufgerufen und dadurch die Freigabe von CPU-Zeit erzwungen.

Auswertung nach Quartalen und Kalenderwochen

Wenn Sie Daten in Ihren Berichten beispielsweise nach Quartal oder der Kalenderwoche gruppieren möchten, kommen in den entsprechenden Abfragen häufig berechnete Zusatzfelder zum Einsatz. Beispielsweise:

Quartal: DatePart(„q“;[BestellDatum])“

oder

KW: DatePart(„ww“;[BestellDatum])

Wenig bekannt ist die Tatsache, dass es mit einem kleinen Trick wesentlich schneller und einfacher geht, denn die Funktion „Sortieren und Gruppieren“ kann fast die ganze Arbeit für Sie übernehmen:

1. Öffnen Sie den gewünschten Bericht im Entwurfsmodus.

2. Wählen Sie das Menü ANSICHT-SORTIEREN UND GRUPPIEREN an.

3. Stellen Sie in der Spalte „Feld/ Ausdruck“ das Datumsfeld ein, nach dem gruppiert werden soll, also beispielsweise „Bestelldatum“ oder „Versanddatum“.

4. Im Dropdown-Menü der Eigenschaft „Gruppieren nach“ können Sie nun das gewünschte Kriterium, also z. B. „Quartal“ oder „Woche“, einstellen.

Diese Gruppierungsmöglichkeiten sparen zwar schon eine Menge Arbeit, aber leider hat Microsoft die häufig geforderte Gruppierung nach Halbjahren vergessen, die vor allem bei längeren Auswertungszeiträumen wichtig ist.

 

Eine entsprechende Gruppierung lässt sich aber mit wenig Aufwand nachrüsten:

1. Legen Sie in einem beliebigen VBAModul Ihrer Datenbank die folgende Funktion an:

Function Halbjahr(aDate As Date)
As Integer
Select Case Month(aDate)
Case 1, 2, 3, 4, 5, 6:
Halbjahr = 1
Case 7, 8, 9, 10, 11, 12:
Halbjahr = 2
End Select
End Function

2. Im Dialog „Sortieren und Gruppieren“ geben Sie dann im Feld „Feld/Ausdruck“ die folgende Anweisung ein:

=Halbjahr([Versanddatum])

„Versanddatum“ ersetzen Sie dabei durch das Feld, das als Basis für die Gruppierung herangezogen werden soll.

Zugriff auf Zwischenablage per API

Obwohl die Zwischenablage zu den wichtigsten Elementen von Windows gehört, verfügt Access selbst in der aktuellsten Version über keinerlei Funktionen, um Daten in die Zwischenablage übertragen oder aus der Zwischenablage übernehmen zu können. So ist es nicht möglich, beispielsweise eine Adresse über die Zwischenablage an eine andere Office- Anwendung zu übergeben oder das Ergebnis einer Berechnung aus Excel in einen Datensatz einzufügen. Glücklicherweise stellt das API jedoch verschiedene Funktionen bereit, mit deren Hilfe sich von Access aus auf die Zwischenablage zugreifen lässt:

Declare Function OpenClipboard Lib „user32“ (ByVal hwnd As Long) As Long
Declare Function SetClipboardData Lib „user32“ (ByVal wFormat As Long, ByVal hMem As Long) As Long
Declare Function GetClipboardData Lib „user32“ (ByVal wFormat As Long) As Long
Declare Function CloseClipboard Lib „user32“ () As Long

Der Einsatz dieser API-Funktionen gestaltet sich jedoch recht kompliziert: Da Windows ein Multitasking-Betriebssystem ist und somit Anwendungen gleichzeitig auf die Zwischenablage zugreifen können, sind bestimmte Regeln einzuhalten.

So muss für den Zugriff auf die Zwischenablage zunächst über „OpenClipboard()“ ein eindeutiger Handle angefordert werden, der beim Aufruf weiterer Zwischenablage- Funktionen wie „SetClipboard- Data()“ (Daten in der Zwischenablage ablegen) oder „GetClipboardData()“ (Daten aus der Zwischenablage abrufen) jeweils als Parameter anzugeben ist.

Die Daten werden nicht einfach als Zeichenkette in der Zwischenablage abgelegt oder von dort in eine Zeichenkette eingelesen, vielmehr erfolgt der Austausch über einen geschützten Speicherblock, dessen Adresse zum Beispiel bei „SetClipboard- Data()“ als Parameter „hMem“ anzugeben ist beziehungsweise dessen Adresse von „GetClipboardData()“ als Funktionsergebnis geliefert wird. Da VBA keine Speicheroperationen unterstützt, müssen weitere API-Funktionen wie „Global- Alloc()“ oder „lStrCpy()“ für die Reservierung von Speicherblöcken und die Übertragung von Daten in diesen Speicherblock eingesetzt werden.

Um also zum Beispiel einen Text in der Zwischenablage abzulegen, sind hintereinander die Funktionen „OpenClipboard()“ (Zugriff öffnen), „GlobalAlloc()“ (Speicherblock reservieren), „lStrCpy()“ (Daten in Speicherblock übertragen), „SetClipboardData()“ (Speicherblock an Zwischenablage übergeben), „CloseClipboard()“ (Zugriff schließen) und „GlobalFree()“ (Speicherblock wieder freigeben) aufzurufen.

So nutzen Sie das vorbereitete Klassenmodul

Damit Sie sich mit diesen „Aufruforgien“ nicht herumplagen müssen, haben wir ein Klassenmodul „ClpBrd“ vorbereitet, das Sie universell in eigene Projekte einbinden können und das es Ihnen erlaubt, Texte aus Datensätzen in der Zwischenablage abzulegen oder Texte aus der Zwischenablage auszulesen und in Felder oder Datensätze einzufügen. In der Beispieldatenbank ZWIABLG.MDB (kostenloser Download auf www.access-aktuell. de mit dem Download-Code DXF) finden Sie das bereits erwähnte Klassenmodul „ClpBrd“, das Ihnen vier Methoden zur Verfügung stellt:

Methode

Funktion

SetData

zum Ablegen von Texten
in der Zwischenablage

GetData


zum Auslesen von Texten
aus der Zwischenablage

Clear

zum Löschen
der Zwischenablage

ClpBrdEmpty

zum Prüfen
der Zwischenablage

Der Zugriff auf die Methoden/Eigenschaften eines Klassenmoduls erfolgt über eine Objektvariable, die zunächst initialisiert werden muss:

Dim ZA As New ClpBrd

Hier wird eine Objektvariable „ZA“ vom Typ „ClpBrd“ deklariert, die für den Aufruf der im Klassenmodul definierten Methoden verwendet wird. Durch das Schlüsselwort „New“ generiert Access eine neue Instanz des Klassenmoduls und lädt es für den sofortigen Zugriff auf dessen Methoden/ Eigenschaften in den Speicher. Diese Anweisung müssen Sie in jede Ereignisprozedur oder VBA-Routine, aus der heraus Sie auf die Zwischenablage zugreifen möchten, aufnehmen.

Daten in der Zwischenablage ablegen

Um nun beispielsweise einen Feldinhalt über die Methode „SetData“ in die Zwischenablage zu kopieren, käme folgende Anweisung zum Einsatz:

Dim ZA As New ClpBrd
…..
ZA.SetData Me.Ort
…..

„SetData“ erwartet lediglich einen einzigen Parameter: Den in die Zwischenablage zu übertragenden Text. Diesen können Sie, wie oben gezeigt, als Feldnamen, aber auch als Konstante, Variable oder als Ausdruck angeben:

Dim ZA As New ClpBrd, strOrt as String
…..
strOrt = Me.Ort
ZA.SetData strOrt
…..
ZA.SetData „Hamburg“
…..
ZA.SetData
DLookup(„[Ort]“,“PLZOrte“, „[PLZ]= 20111“)
…..

Der zu übertragene Text kann beliebig lang sein und beispielsweise ein komplettes Memofeld umfassen, er sollte aber eine maximale Länge von ca. 64.000 Zeichen nicht überschreiten. Diese Beschränkung resultiert daraus, dass der Zugriff auf die Zwischenablage über Windows-API-Funktionen mithilfe eines geschützten Speicherblocks erfolgt, der (ebenfalls über API-Funktionen) separat angefordert und reserviert werden muss. Mit Access-Variablen kann hier nicht gearbeitet werden, da sich diese „beweglich“ im Speicher befinden und ihre Adresse ändern können – schlimmstenfalls würde eine später aufgerufene API-Funktion dadurch auf einen nicht initialisierten Speicherbereich zugreifen und Access oder andere Anwendungen zum Absturz bringen. Die Größe von ca. 64.000 Zeichen ergibt sich sozusagen aus historischen Gründen: Früher war die Zwischenablage auf Objekte von maximal 64 KB Größe beschränkt, viele Anwendungen, aber auch Windows-internes Zubehör, verwenden immer noch Speicherbereiche in dieser Größe, sodass die Übertragung von größeren Objekten unter Umständen zu Problemen führen kann.

Bei Bedarf können Sie „SetData“ auch als Funktion einsetzen. Das Funktionsergebnis ist „True“, wenn die Daten erfolgreich in der Zwischenablage abgelegt werden konnten, andernfalls ist es „False“:

PDim ZA As New ClpBrd, strOrt as String
…..
strOrt = Me.Ort
If ZA.SetData(strOrt) = False Then
Beep
MsgBox „Fehler beim Zugriff auf Zwischenablage…“
Exit Sub
End If

Daten aus der Zwischenablage lesen

Analog zu „SetData“ setzen Sie die Methode „GetData“ ein. Diese überträgt den in der Zwischenablage abgelegten Text in eine Variable oder in ein Feld:

PDim ZA As New ClpBrd, strOrt as String
Dim db as Database, rs as Recordset
…..
strOrt = ZA.GetData()
…..
Me.Ort = ZA.GetData()
…..
Set db = CurrentDb()
Set rs = db.OpenRecordset(„Adressen“)
rs.AddNew
…..
rs(„Ort“) = ZA.GetData()
…..
rs.Update
rs.Close
…..

Bitte beachten Sie: „GetData()“ liefert nur Text als Ergebnis. Wenn sich in der Zwischenablage ein Objekt mit anderem Format, beispielsweise eine Bitmap, befindet, gibt „SetData“ eine Fehlermeldung aus und liefert als Ergebnis eine leere Zeichenkette („“)! Die Größe des Puffers für die Übertragung in die Zwischenablage haben wir aus Geschwindigkeitsgründen auf 32 KB beschränkt. Wenn Sie umfangreichere Texte zu übertragen haben, können Sie die Größe des Puffers im Klassenmodul „ClpBrd“ über die Konstante „MAXSIZE“ ändern.

Inhalt der Zwischenablage löschen

Über die Methode „Clear“ können Sie den Inhalt der Zwischenablage löschen. Das sollten Sie beispielsweise in Datenbanken, in denen Sie sensible Informationen verarbeiten, vor dem Beenden der Datenbank unbedingt tun. Andernfalls könnte ein Anwender, der nach Ihnen mit dem PC arbeitet, die Daten zum Beispiel in Word einfügen und dort einsehen. Am einfachsten erfolgt die Löschung der Zwischenablage automatisch beim Schließen eines jeden Formulars:

Private Sub Form_Close()
Dim ZA As New ClpBrd
ZA.Clear
End Sub

Zwischenablage prüfen

Außerdem haben wir im Klassenmodul „ClpBrd“ noch die Methode „ClpBrdEmpty()“ implementiert, über die Sie prüfen können, ob sich ein Objekt in der Zwischenablage befindet und ob es sich dabei um den Datentyp „Text/String“ handelt. Auf diese Weise lässt sich beispielsweise in einer Ereignisprozedur einer Schaltfläche zunächst prüfen, ob einfügbarer Text vorhanden ist, und gegebenenfalls eine Meldung anzeigen:

Private Sub btnCheck_Click()
Dim ZA As New ClpBrd, strCBData As String
Beep
If ZA.ClpBrdEmpty() Then
MsgBox „Zwischenablage ist leer “ & „oder enthält keinen Text…“
Else
strCBData = ZA.GetData()
MsgBox „Zwischenablage enthält Text: “ + vbCrLf + vbCrLf + Left$(strCBData, 50) + „…“
End If
End Sub

Dieses einfache Beispiel prüft, ob die Zwischenablage einfügbaren Text enthält – wenn ja, werden davon die ersten 50 Zeichen als „Muster“ angezeigt, wenn nicht, geben wir eine entsprechende Meldung aus.

Damit Sie sich die Funktionsweise gleich einmal in der Praxis anschauen können, haben wir in der Beispieldatenbank ZWIABLG.MDB eine kleine Adressverwaltung vorbereitet, deren Formular „Adressen“ beim Start der Datenbank automatisch geöffnet wird. In diesem Formular finden Sie unter anderem zwei Schaltflächen „Adresse in ZA“ und „Import aus ZA“.

Über die Schaltfläche ADRESSE IN ZA wird die aktuell angezeigte Adresse als Text in die Zwischenablage übertragen und kann von dort aus zum Beispiel in Word als Basis für einen Brief eingefügt werden.

Über die Schaltfläche IMPORT AUS ZA können Sie per Mausklick einen in Word erstellten und dort in die Zwischenablage kopierten Brief in das Memofeld „Briefe“ einfügen bzw. an eventuell vorhandene Inhalte anhängen. So ist eine schnelle Übersicht der bislang abgewickelten Korrespondenz von hier aus möglich, ohne dass Word dazu extra gestartet werden muss.

Anpassung an individuelle Anforderungen

Wie bereits erwähnt, haben wir den Puffer für die Übertragung von Daten aus der Zwischenablage auf 32 KB begrenzt, um nicht über Gebühr Speicher zu belegen und um die Ausführungsgeschwindigkeit von „GetData()“ nicht unnötig zu verlängern. Bei Bedarf ändern Sie die Größe des Puffers wie folgt:

1. Wechseln Sie im Datenbankfenster in den Bereich „Module“ und öffnen Sie das Klassenmodul „ClpBrd“ mit einem Klick auf die Schaltfläche ENTWURF.

2. Im allgemeinen Teil finden Sie im Bereich „Deklarationen“ am Ende die Konstante „MaxSize“.

3. Ändern Sie sie auf den gewünschten Wert.

Fehlermeldungen unterdrücken

Wir haben in allen Methoden verschiedene Prüfungen eingebaut, die im Falle eines Falles Fehlermeldungen anzeigen. Um diese zu unterdrücken und nur die Funktionsergebnisse auszuwerten, kommentieren Sie die entsprechenden Zeilen wie am folgenden Beispiel gezeigt aus:

Function GetData()
strCBData = „“
If ClpBrdEmpty() Then
‚Beep
‚MsgBox „ClpBrd/Get:
Zwischenablage ist leer…“,_
vbCritical
Exit Function
End If
…..


Modul: modAdressen 


Modul: ClpBrd

 

Vorhergehenden Feldinhalt ermitteln

Datenbank

Für viele Anwendungen ist es notwendig, Informationen aus anderen Datensätzen in ein Formular zu übernehmen. Zum Beispiel: Beim Erfassen von Zählerständen in einer Tabelle, möchten Sie gerne auf den vorhergehenden Datensatz zugreifen, den letzten Zählerstand auslesen und dann vom aktuellen Zählerstand subtrahieren. Access bietet verschiedene Möglichkeiten, um dieses Problem zu lösen. Unter anderem könnten Sie eine VBA-Prozedur schreiben, aber wesentlich einfacher und schneller ist der Einsatz der so genannten Aggregatfunktionen von Access. Mit ihrer Hilfe können Sie Daten aus beliebigen Tabellen oder Abfragen auslesen und datensatzunabhängig in einem Formular anzeigen.

An einem konkreten Beispiel lässt sich der Einsatz der Aggregatsfunktionen am einfachsten erklären: Nehmen wir an, dass Sie in einer Tabelle „tblZähler“ jeden Tag irgendeinen aktuellen Zählerstand (beispielsweise vom Kopierer) erfassen möchten. Die Tabelle weist also die Felder „Datum“ und „Zählerstand“ auf. Die wichtigste Voraussetzung zum Auslesen des Zählerstandes vom vorhergehenden Tag ist es, dass die Tabelle zusätzlich über einen Primärschlüssel verfügt, der die Datensätze aufsteigend durchnumeriert. In unserem Fall hat das Feld den Namen „ID“.

Auf Basis dieser Tabelle erstellen Sie nun ein Formular „frmZähler“, das alle drei Felder enthält. Zur Anzeige des Zählerstandes vom vorhergehenden Tag fügen Sie ein ungebundenes Textfeld ein, dem Sie im Eigenschaftenfenster den Namen „“ZaehlerAlt“ geben. Interessant wird es nun bei der Datenherkunft dieses Feldes. Geben Sie hier folgendes ein:

=DomWert(„[Zählerstand]“;“tblZähl er“;“[ID]=“ & [Formulare]![frm- Zähler]![ID]-1)

Die Funktion DomWert hat die folgende Syntax:

=DomWert(„<Feld>“;“<Tabelle/Abfrage >“;“<Kriterien>“)

Geliefert wird das angegeben Feld aus der Tabelle oder Abfrage des Datensatzes, auf den die definierten Kriterien zutreffen.

In unserem Beispiel wählen die Kriterien den Datensatz aus, dessen ID-Nummer um den Wert 1 niedriger ist als die IDNummer des augenblicklich angezeigten Datensatzes.

Dabei handelt es sich um den Datensatz des vorangegangenen Tages und hier findet sich dann auch der gesuchte alte Zählerstand.

Die Differenz zwischen altem und neuem Zählerstand ermitteln Sie dann wiederum in einem ungebundenen Textfeld, dessen Datenherkunft folgendermaßen festgelegt ist:

=[Zählerstand]-[ZaehlerAlt]

Diese Lösung hilft natürlich nur in einigen speziellen Situationen weiter, aber sie zeigt sehr gut, wie sich die Aggregatsfunktionen von Access nutzbringend in Formularen einsetzen lassen. Im nächsten Schritt können wir uns nun mit einem etwas komplizierteren Thema befassen, das ebenfalls mehrere Male als Lösungswunsch von unseren Lesern geäußert wurde: Beim Erfassen von Bestellungen wird im Formular der Name des Kunden per Kombinationsfeld ausgewählt.

Wünschenswert wäre es nun, direkt beim Annehmen der neuen Bestellung einige zusätzliche Informationen über den Kunden angezeigt zu bekommen.

Beispielsweise wäre es nützlich, das Datum der letzten Bestellung zu erfahren. Anhand des Formulars „Bestellungen“ in der Datenbank NORDWIND.MDB, können Sie die Technik im folgenden Schritt für Schritt nachvollziehen:

  1. Öffnen Sie die Datenbank NORDWIND. MDB wechseln Sie auf das Register „Formulare“ und klicken Sie das Formular „Bestellungen“ mit der rechten Maustaste an.
  2. Rufen Sie das Kontextmenü KOPIEREN auf, klicken Sie mit der rechten Maustaste in das Datenbank-Fenster und wählen Sie EINFÜGEN an.
  3. Geben Sie dem neuen Formular den Namen „Bestellungen_DLookup“ und bestätigen Sie mit OK.
  4. Fügen Sie ein ungebundenes Textfeld ein, und rufen Sie das Eigenschaftenfenster auf.
  5. Geben Sie als Datenherkunft die folgende Funktion ein:
    =DomMax(„[Bestelldatum]“;“Bestellungen“;“[ Kunden-Code]='“ & [Formulare]![Bestellungen_DLook up]![Kunden-Code] & „‚ And [Bestelldatum] < #“ & Format$( Jetzt();“mm/tt/jj“) & „#“)

  6. Wenn Sie nun wieder in die Formularansicht wechseln, wird in dem ungebundenen Textfeld für jeden Kunden das Datum der letzten Bestellung angezeigt.

Und so arbeitet die Funktion: Über die Kriterien werden alle Bestellungen des Kunden ausgewählt, der zur Zeit im Formular zu sehen ist. Aus diesen Datensätzen liefert DomMax dann den größten Wert des Datumsfeldes, was dem Datum der letzten Bestellung entspricht. Wichtig dabei ist noch, dass die Kriterien explizit die Bestellung des aktuellen Tages ausschließen. Andernfalls würde Access beim Erfassen einer neuen Bestellung natürlich dieses Datum anzeigen.

Unterformulare sperren und automatisch freigeben

Problem

In unserer Kundenverwaltung befindet sich ein Unterformular, über das Zusatzinformationen zum jeweiligen Kunden wie Telefonate, Besuche, Rabattabsprachen etc. erfasst werden können. Diese Informationen werden in einer zweiten Tabelle gespeichert, die Verknüpfung er folgt über die Kundennummer. Beim Anlegen neuer Kunden möchten wir sicherstellen, dass zunächst alle Basisdaten des Kunden erfasst sind, bevor Zusatzinformationen im Unterformular eingegeben werden können.

Wie kann man das am besten erreichen?

Lösung

Das Unterformular-Steuerelement verfügt wie andere Steuerelemente über eine Eigenschaft „Aktiviert“ (Enabled).

Diese Eigenschaft setzen Sie über die Ereignisprozedur „Beim Anzeigen“ bei neuen Datensätzen zunächst auf „Nein“ (False):

Private Sub Form_Current()
If Me.NewRecord Then
Me. UFoZusatz.Enabled = False
Else
Me. UFoZusatz.Enabled = True
End If
End Sub

Für die Ereignisprozeduren „Nach Aktualisierung der „Pflichtfelder“ (zum Bei – spiel „Firma“, „Strasse“, „Ort“) setzen Sie die folgende Überprüfung ein:

Private Sub Firma_AfterUpdate()
If Me.Firma <> „“ And Me.Strasse <> „“ And Me.Ort <> „“ Then
Me.UFoZusatz.Enabled = True
End If
End Sub

Diese Anweisungen schalten das Unterformular erst dann frei, wenn in allen drei „Pflichtfeldern“ Eingaben vorhanden sind.

Uhrzeit berechnen

Stunden ausrechnen

[Überstunden-geleistet] = Hour([Arbeitszeit-bis]) – Hour([Arbeitszeit-von])


Minuten ausrechnen

[Überstunden-geleistet] = Minute([Arbeitszeit-bis]) – Minute([Arbeitszeit-von])


Zeitraum (Stunden und Minuten ausrechnen)

A = Hour([Arbeitszeit-bis]) – Hour([Arbeitszeit-von])

B = (Minute([Arbeitszeit-bis]) – Minute([Arbeitszeit-von])) / 60

[Arbeitzeit-geleistet] = A + B

Titelleiste eines Formulares blinken lassen

Datenbank

Häufig benutzen Sie Formulare, um dem Anwender wichtige Hinweise anzuzeigen. Sind nun mehrere Formulare gleichzeitig geöffnet, können solche Hinweise schnell übersehen werden.

Um die Aufmerksamkeit des Anwenders trotzdem auf diesen Hinweis zu lenken, kann zunächst das Formular optisch besonders auffällig gestaltet werden, indem Sie zum Beispiel den Hintergrund auf die Farbe „Rot“ sowie die Schrift auf „Fett“ und „Gelb“ einstellen.

Eine weitere Möglichkeit, die Aufmerksamkeit des Anwenders auf den Hinweis zu lenken, besteht darin, die Titelleiste des Formulars mit dem Hinweis zusätzlich blinken zu lassen.

Für diesen Zweck können Sie die APIFunktion „FlashWindow“ nutzen, die als Parameter einmal einen Handle „hWnd“ auf das betreffende Fenster und einen Schalter „bInvert“ erwartet.

Ein Schalter legt fest, ob die Titelleiste des Fensters normal (bInvert= 0) oder invertiert (bInvert= 1) angezeigt werden soll. Über die Ereignisprozedur des Timers eines Formulars, dessen Eigenschaft „Zeitgeberintervall“ beispielsweise auf den Wert „500“ eingestellt ist, können Sie so die Titelleiste auffällig blinken lassen.

Die Ereignisprozedur „Timer“ des Formulars wird sofort nach dem Öffnen des Formulars gemäß eingestelltem Intervall aufgerufen und invertiert die Titelleiste entsprechend:

Sub Form_Timer ()
Dim X As Variant
X = FlashWindow(Me.hWnd, 1)
End Sub

Mit der Ereignisprozedur „Form_Unload()“ oder „btnOK_Click()“ einer Schaltfläche zur Bestätigung der Meldung wird die Invertierung dann wieder zurückgesetzt und die Titelleiste normal angezeigt:

Sub btnOK_Click ()
Dim X As Variant
X = FlashWindow(Me.hWnd, 0)
DoCmd Close
End Sub

Allerdings nützt die blinkende Titelleiste eines Formulars wenig, wenn das Access- Fenster minimiert wurde, weil beispielsweise in einer anderen Anwendung etwas nachgeschlagen werden muss.

Sie können jedoch den gleichen Mechanismus einsetzen, um auch die Titelleiste des Access-Fensters blinken zu lassen:

X = FlashWindow(Application. hWndAccessApp, 1)

Anstelle des Handles auf das Formular wird hier der Handle auf das Access- Fenster übergeben und so deren Titelleiste zum Blinken gebracht. Für eine Demonstration dieser Funktion öffnen Sie in der Beispieldatenbank das Formular „Test Access-Fenster blinken lassen“.


Speichern Sie das Modul „modFlashWindow“ ab.