|  | Unser Angebot für Sie! Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'! |
| | | | | |
Zusammenfassung
Lernen Sie Tipps und Tricks kennen, um sich den Programmieralltag zu erleichtern.
Techniken
DoCmd.Close, Dateien schreiben, Kontestmenüs ermitteln
Voraussetzungen
Access 2000 oder höher
Beispieldateien
-
Shortlink
652
Tipps und Tricks
André Minhorst, Duisburg
Es sind die kleinen Kniffe, die uns den Alltag beim Programmieren von Access-Anwendungen erleichtern. In dieser Ausgabe von Access im Unternehmen zeigen wir Ihnen zum Beispiel, wie Sie den Datensatzwechsel in Formularen steuern, bei Problemen mit DoCmd.OpenForms reagieren, oder einen kompletten Datensatz im Endlosformular markieren.
DoCmd.Close und seine Tücken
Die Anweisung DoCmd.Close schließt ohne Parameter das aktuelle Objekt, und mit den beiden Parametern ObjectType und ObjectName, für die man den Objekttyp (meist acForm oder acReport) und den Objektnamen (etwa frmBeispiel oder rptBeispiel) eingibt, beendet es die Anzeige des angegebenen Objekts.
Die in der Überschrift erwähnte Tücke bezieht sich ausschließlich auf Formulare, die an eine Datenherkunft, wie eine Tabelle oder eine Abfrage, gebunden sind. Dort sorgt das Schließen eines Formulars per DoCmd.Close für das Speichern des aktuellen Datensatzes.
Aber leider nicht immer, so zum Beispiel bei Datensätzen, denen Sie einen bereits vorhandenen Wert für ein Feld mit eindeutigem Index hinzugefügt haben. Die passende Tabelle sieht im Entwurf samt Indizes wie in Abb. 1 aus. Die Fehlermeldung, die beim zweimaligen Wert des gleichen Datensatzes im eindeutigen Feld Beispielfeld auftaucht, hat die Fehlernummer 3022 und besagt, dass man versucht, einen Wert hinzuzufügen, nachdem ein Index, ein Primärschlüssel oder eine Beziehung doppelte Werte enthalten würde.
Abb. 1: Eindeutiger Index eines Tabellenfelds
Erstellen Sie nun ein Formular, das die beiden Felder der Beispieltabelle und eine Schaltfläche mit dem Namen cmdOK enthält (s. Abb. 2), und legen Sie die folgende Ereignisprozedur für diese Schaltfläche an:
Abb. 2: Formular zum Testen des Verhaltens von DoCmd.Close
Private Sub cmdOK_Click()
DoCmd.Close acForm, Me.Name
End Sub
Geben Sie in den ersten Datensatz einen Wert für das Feld Beispielfeld ein und klicken Sie auf OK. Wenn Sie in der Tabelle tblBeispiel nachsehen, finden Sie den neu angelegten Datensatz dort vor. Öffnen Sie das Formular erneut, wechseln Sie zum zweiten Datensatz und geben Sie den gleichen Wert wie zuvor in das Feld Beispielfeld ein.
Klicken Sie auf OK, ohne vorher den Datensatz per Klick auf den Datensatzmarkierer oder durch Wechseln zu einem anderen Datensatz zu speichern. Die erste Überraschung: Es erscheint keine Fehlermeldung. Die zweite Überraschung: Ein Blick in die Tabelle tblBeispiel zeigt, dass der Datensatz kommentarlos überhaupt nicht angelegt wurde.
Ein Blick in die Online-Hilfe der Close-Methode zeigt, dass dieses Verhalten zumindest nicht dokumentiert ist: Dort ist lediglich die Rede davon, dass Felder, für die Sie die Required-Eigenschaft auf True eingestellt haben, für einen kommentarlosen Abbruch des Speichervorgangs sorgen können, wenn diese keinen Wert enthalten.
Probleme können hier beispielsweise entstehen, wenn ein Unternehmen seine Mitarbeiter mit Access verwaltet.
Trägt man einen neuen Mitarbeiter, dessen Name bereits vorhanden ist, mit einem Formular wie oben beschrieben in die Mitarbeitertabelle ein, bricht Access den Speichervorgang bei alleiniger Anwendung von DoCmd.Close kommentarlos ab.
Wenn man dann nach dem frisch eingegebenen Mitarbeiter sucht, stößt man vermutlich auf den bereits vorhandenen Mitarbeiter und reibt sich die Augen, da sein Datensatz ganz andere Detailinformationen aufweisen dürfte als der des soeben eingegebenen Mitarbeiters.
Das größte Problem ist, dieses Fehlverhalten zu erkennen. Seine Behebung ist einfach: Sie brauchen den Datensatz einfach nur vor dem Schließen des Formulars zu speichern, und zwar mit der folgenden Anweisung:
Me.Dirty = False
Wenn der neue Datensatz wegen bestehender eindeutiger Indizes nicht angelegt werden kann, meldet Access Fehler 3022, den Sie etwa wie folgt abfangen können:
Private Sub cmdOK_Click()
On Error Resume Next
Me.Dirty = False
If Err.Number = 3022 Then
MsgBox Err.Number & " " & Err.Description
Exit Sub
End If
On Error GoTo 0
DoCmd.Close acForm, Me.Name
End Sub
Dateien schreiben ohne Hindernisse
Hier und da schreiben Access-Anwendungen mal Daten oder sonstige Informationen in Textdateien. Ein ganz einfaches Beispiel sieht so aus:
Open "c:\test.txt" For Output As #1
Print #1, "Beispielzeile"
Print #1, "Noch eine Beispielzeile"
Close #1
Der Ausdruck #1 dient dabei als Dateinummer, wobei Sie auch jede andere Zahl zwischen 1 und 255 wählen können.
Wenn Sie mehrere Dateien gleichzeitig beschreiben oder auch auf unterschiedliche Art auf verschiedene Dateien zugreifen möchten, verwenden Sie einfach mehrere Dateinummern wie in folgendem Beispiel:
Open "c:\test1.txt" For Output As #1
Open "c:\test2.txt" For Output As #2
Print #1, "Beispielzeile in Datei 1"
Print #2, "Beispielzeile in Datei 2"
Close #1
Close #2
Warum wir Ihnen das zeigen? Nun: Wenn Sie mal nicht nur eine Datei mit Open öffnen, sollten Sie die Dateinummern im Blick behalten. Es könnte sonst zum Beispiel sein, dass Sie nach dem Öffnen einer Datei mit der Nummer #1 eine Routine aufrufen, deren genauen Ablauf Sie gar nicht mehr so genau im Kopf haben, die aber ebenfalls auf eine Datei mit dieser Nummer zugreift. Dies löst dann den Laufzeitfehler 55, Datei bereits geöffnet aus.
Vielleicht vergessen Sie auch einfach, die Close-Methode für eine soeben geöffnete Datei aufzurufen, oder diese wird wegen eines vorher auftretenden Abbruchs nicht mehr erreicht: Beim nächsten Zugriff mit der gleichen Dateinummer tritt trotzdem ein Fehler auf.
In diesem Fall würde die Holzhammermethode helfen, bei der man vor dem Öffnen einfach eine eventuell unter dieser Dateinummer geöffnete Datei schließt.
Wenn jedoch tatsächlich zwischendurch eine andere Datei geöffnet wurde, würde man diese damit schließen und gegebenenfalls unerklärliche Verhaltensweisen hervorrufen, weil Daten in die falschen Dateien geschrieben werden.
Abhilfe schafft die FreeFile-Methode von VBA: Sie ermittelt die nächste nicht benutzte Dateinummer, die Sie ganz einfach einer Variablen zuweisen. Diese verwenden Sie dann im folgenden Verlauf statt eines Ausdrucks wie #1, wobei die Variable in der Print-, Input- und Get-Anweisung gegenüber dem Open- und Close-Befehl jeweils um eine führende # ergänzt werden muss:
Dim intFile As Integer
intFile = FreeFile
Open "c:\test.txt" For Output As intFile
Print #intFile, "Test"
Bei 255 Dateien ist übrigens noch nicht Schluss: Wenn Sie der FreeFile-Methode den Wert 1 als Parameter übergeben, liefert diese die nächste freie Dateinummer ab der Zahl 256.
Welches Kontextmenü hätten's denn gern?
Wenn Sie schon mal ein eingebautes Kontextmenü um einen Befehl erweitern wollten, haben Sie vermutlich erstmal eine Menge Zeit damit verbracht, den Namen des gewünschten Kontextmenüs herauszufinden.
Namen werden nämlich beim Anzeigen des Kontextmenüs nicht angezeigt und die Bezeichnungen lassen sich unter VBA auch nur auf Englisch ausgeben.
Es gibt jedoch eine ganz einfache Möglichkeit, bei der Sie lediglich jedem einzelnen Kontextmenü ein neues, temporäres Steuerelement hinzufügen müssen, das für die Eigenschaft Caption die englische Bezeichnung der Kontextmenüleiste erhält.
Die folgende Routine erledigt diese Aufgabe, indem sie alle CommandBar-Elemente von Access durchläuft und für alle eingebauten Kontextmenüs ein CommandBarControl mit der entsprechenden Beschriftung hinzufügt.
Public Sub TestCommandbars()
Dim cbr As CommandBar
Dim cbc As CommandBarControl
On Error Resume Next
For Each cbr In CommandBars
If cbr.BuiltIn = True And _
cbr.Type = msoBarTypePopup Then
Set cbc = _
cbr.Controls.Add(1, , , , True)
With cbc
.Caption = cbr.name
End With
End If
Next cbr
End Sub
Der schwierigste Teil der Arbeit ist bereits erledigt. Sie brauchen nur noch das Kontextmenü aufzurufen, dessen englische Bezeichnung Sie ermitteln wollen. Diese wird einfach am Ende des Kontextmenüs angezeigt, wie Abb. 3 zeigt.
Abb. 3: Ermitteln des Kontextmenünamens mit einem kleinen Trick
Hochkommata verdoppeln und Fehler verhindern
Wer gelegentlich Daten per SQL-Aktionsabfrage zu einer Tabelle hinzufügt oder bestehende Daten ändert, ist vielleicht schon auf folgenden Fehler gestoßen.
Sie möchten einem Textfeld einen Wert hinzufügen, der irgendwo her kommt - beispielsweise aus einer Excel- oder XML-Datei, vielleicht aber auch aus einer Benutzereingabe -, und verwenden dazu Anweisungen wie die folgende.
Grundlage dafür ist eine Tabelle namens tblTest mit den zwei Feldern ID (Autowert und Primärschlüssel) und Teststring (Text), und der einzufügende Wert stammt hier einfach aus einer Variablen:
Dim strTest As String
Dim db As DAO.Database
Set db = CurrentDb
strTest = "lala'lala"
db.Execute "INSERT INTO tblTest(Teststring) µ
VALUES('" & strTest & "')", dbFailOnError
Dies löst den Fehler mit der Nummer 3075 und der Fehlermeldung Syntaxfehler (fehlender Operator) in Abfrageausdruck ''lala'lala')'. aus.
Worin genau liegt hier der Fehler? Nun: Der hier dynamisch zusammengesetzte Abfrageausdruck lautet wie folgt:
INSERT INTO tblTest(Teststring) VALUES('lala'lala')
Beim Auswerten dieses Ausdrucks denkt Access, dass der einzufügende Wert nach dem zweiten Hochkomma abgeschlossen ist, und kann das unmittelbar folgende lala' nicht interpretieren, weil es hier normalerweise direkt die schließende Klammer erwartet.
Damit dieser Fehler nicht auftritt, müssen Sie einfach nur die innerhalb einzufügender Werte auftretenden Hochkommata verdoppeln, das heißt, dass Sie jedes Hochkomma durch zwei aufeinanderfolgende Hochkommata ersetzen. Das erledigt die Replace-Anweisung wie in der folgenden neuen Version der obigen fehlerhaften Zeile:
db.Execute "INSERT INTO tblTest(Teststring) µ
VALUES('" & Replace(strTest, "'", "''") µ
& "')", dbFailOnError
Der besseren Übersicht halber können Sie das Ersetzen eventuell vorkommender Hochkommata auch vorab erledigen:
strTest = Replace(strTest, "'", "''")
db.Execute "INSERT INTO tblTest(Teststring) µ
VALUES('" & strTest & "')", dbFailOnError
Diese Maßnahme sollten Sie übrigens überall ergreifen, wo Hochkommata in einzufügenden oder zu aktualisierenden Daten auftauchen könnten.
|