Home > Artikel > Ausgabe 11/2015 > DoCmd- und RunCommand-Anweisungen

DoCmd- und RunCommand-Anweisungen

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Aktionen, die Sie über die Oberfläche von Access durchführen, lassen sich fast alle auch über VBA anstoßen. Für die hinter Menüs, Kontextmenüs und Ribbon liegenden Befehle gibt es Pendants, welche sich in zahlreichen Methoden vor allem des DoCmd-Objekts und der RunCommand-Anweisung verstecken. Über diese VBA-Funktionen lassen sich komplexe Aufgaben mit wenig Aufwand erledigen. Das ist Grund genug für eine ausführlichere Übersicht.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1511_DocmdAnweisung.accdb

Unterschiede zwischen DoCmd und RunCommand

Zunächst handelt es sich bei RunCommand um eine direkte Methode der Access.Application-Instanz. DoCmd hingegen ist ein Eigenschaftsobjekt von Application, das generell verfügbar ist:

Application.RunCommand acCmd-Konstante

Application.DoCmd.

RunCommand nimmt grundsätzlich nur einen einzigen Parameter entgegen, der aus der Enumeration acCommand stammen muss. Das sind Konstanten, die bestimmten Aktionen entsprechen. Wollen Sie etwa ein Fenster, sei es ein Formular oder ein Bericht, maximieren, so lautet die entsprechende Konstante acCmdDocMaximize:

RunCommand acCmdDocMaximize

Die Zahl dieser Konstanten in den aktuellen Access-Versionen liegt bei etwa 600.

Beim DoCmd-Objekt sind es deutlich weniger Methoden, circa 70 nämlich, die dafür aber eine variable Zahl an Parametern aufweisen, mit denen die Aktionen gesteuert werden können. Ein Beispiel für eine Anweisung ohne Parameter wäre

DoCmd.Maximize

Auch dieser Befehl maximiert ein Formular- oder Berichtsfenster, welches aktuell den Fokus besitzt. Eine Methode mit mehreren Parametern wäre

DoCmd.Close acForm, _

"frmAdressen", acSaveYes

Dies schließt das Formular frmAdressen und und speichert seinen Zustand, also vor allem seine Abmessungen, explizit. Auch ein im Entwurfsmodus befindliches Formular wird damit geschlossen und die Änderungen abgespeichert. Ohne den optionalen Parameter acSaveYes würden Sie mit dem Bestätigungsdialog zum Speichern konfrontiert.

Sowohl RunCommand-, wie DoCmd-Anweisungen spiegeln das wieder, was Sie auch über Schaltflächen der Oberfläche erreichen. Es handelt sich deshalb auch immer um Sub-Prozeduren, die keinen Rückgabewert haben. Generell könnte man formulieren, dass RunCommand Anweisungen entspricht, die keine weitere Interaktion erfordern, während die DoCmd-Methoden eher mit den Access-Assistenten zu vergleichen wären, die über mehrere Schritte Angaben abfragen, bevor die eigentliche Aktion ausgeführt wird. Diese vom Assistenten gesammelten Informationen entsprechen dann den Parametern, die die DoCmd-Methode erwartet. Ein Beispiel hierfür wäre der Text-Export-Assistent, der sein Spiegelbild in der Anweisung DoCmd.TransferText hat.

Während die DoCmd-Anweisungen in der Hilfe von Access alle hinreichend dokumentiert sind, sind Sie bei den RunCommand-Konstanten auf den sprechenden Namen oder Experimente angewiesen.

Microsoft selbst hat über alle Versionen von Access hinweg keine Übersicht über die Bedeutung der Konstanten veröffentlicht. Im Zweifel finden Sie Im Internet auf Seiten Dritter weitere Erläuterungen.

Im Folgenden geht es in erster Linie um die Möglichkeiten, die DoCmd eröffnet. Nicht alle Methoden sind aufgeführt, da viele nicht wirklich relevant sind oder nur im Umfeld von Access-Projekten (SQL-Server) Bedeutung haben. Die Methoden sind thematisch zusammengefasst.

Objekte öffnen

Dass sich ein Formular über die DoCmd-Anweisung OpenForm laden lässt, ist Ihnen sicher schon untergekommen. Aber für alle anderen Access-Objekte gibt es ebenfalls äquivalente Methoden, deren wesentliche Vertreter Sie in Listing 1 finden. Interessant sind dabei vor allem die Parameter, welche das Laden steuern.

Sub TestOpenObjects()

     DoCmd.OpenModule "mdlDoCommands", "TestOpenObjects"

         Msg "Modul und Prozedur geöffnet"

     DoCmd.OpenQuery "qryAdressenG", acViewNormal, acReadOnly

         Msg "Abfrage geöffnet"

     DoCmd.OpenReport "rptAdressen", acViewPreview, "Vorname Like 'B*'", acDialog

         Msg "Bericht geöffnet"

     DoCmd.OpenForm "frmAdressen", , , , acFormReadOnly, acDialog, "Test1"

         Msg "Formular war geöffnet"

     DoCmd.OpenTable "tblLaender", acViewNormal, acReadOnly

         Msg "Tabelle geöffnet"

End Sub

Listing 1: Die relevanten Öffnen-Methoden des DoCmd-Objekts

OpenModule ist für den Laufzeitbetrieb einer Datenbank überflüssig. Die Anweisung öffnet ein VBA-Modul, das Sie namentlich angeben. Zusätzlich kann mit weiterem Parameter auch eine Prozedur des Moduls spezifiziert werden, auf die beim Öffnen der Cursor positioniert wird. Die Beispieldatenbanken von Access Basics verwenden den Befehl etwa hin und wieder im Intro-Formular, um beim Start sogleich ein Modul und damit den VBA-Editor zu öffnen, welches von besonderem Interesse sein kann.

OpenQuery öffnet eine Abfrage. Über den View-Parameter steuern Sie dabei, in welcher Gestalt die Abfrage erscheinen soll. Möchten Sie die normale Datenblattansicht, so setzen Sie acViewNormal ein. Für den Entwurfsmodus steht acViewDesign. Weniger bekannt ist, dass acViewPreview die Abfrage in die Seitenansicht für den Druck bringt, womit etwa kontrolliert werden kann, ob das Ergebnis auf eine Seite passt. Diese View-Parameter teilt sich die Anweisung mit den anderen Öffnungsmethoden. Nur sind bei Abfragen die Konstanten acViewReport (Berichtsansicht) und acViewLayout (Layout-Ansicht) nicht erlaubt und führen zum Fehler.

Handelt es sich bei der Abfrage um eine Aktionsabfrage, so hat der View-Parameter keinerlei Bedeutung, denn ein Fenster öffnet sich hier nicht.

Interessant ist der letzte optionale Parameter DataMode, mit dem Sie bestimmen können, ob das Abfrageergebnis editierbar sein soll. acReadOnly führt nämlich zu einer schreibgeschützten Ansicht, während ein acEdit (Vorgabe) die Datensätze bearbeitbar macht, falls die Abfrage selbst das unterstützt.

Die gleichen Parameter, wie für OpenQuery, finden Sie auch bei der Anweisung OpenTable, mit der Sie eine Tabelle öffnen. Auch hier können Sie über DataMode entscheiden, ob die Ansicht schreibgeschützt oder editierbar sein soll.

Umfangreich sind die Parameter, die die zum Laden eines Formulars dienende Anweisung OpenForm erwartet. Bis auf den Namen des Formulars sind diese allerdings alle optional und deshalb auch nicht so bekannt.

Die Ansichtsart steuern Sie wie bei OpenQuery und OpenTable, nur, dass nun auch acViewLayout gestattet ist. Standardmäßig ist acViewNormal voreingestellt. Als zweiten Parameter, im Listing nicht verwendet, können Sie den Namen einer Filterabfrage angeben, die die angezeigte Datensatzmenge einschränkt. Dieses Verfahren ist weitgehend obsolet. Verwenden Sie besser den dritten Parameter für die WhereCondition. Hier können Sie einen SQL-Ausdruck einsetzen, der als Filter dient, etwa:

..., "Nachname LIKE 'H*`'

Das führte dazu, dass nur Datensätze im Formular erschienen, die im Nachnamenfeld mit H beginnen. Die Verwendung dieses Parameters entspricht damit dem Setzen der Formulareigenschaft Filter inklusive dem Aktivieren von FilterOn.

Auch beim Formular kann das Editieren ausgeschaltet werden, indem Sie die Konstante acFormReadOnly für DataMode einsetzen. Und schließlich lässt sich über WindowMode angeben, wie das Formular geladen wird. Der Standard ist acWindowNormal. Nehmen Sie acIcon, so öffnet es sich minimiert. Mit acHidden bleibt es sogar unsichtbar. Schließen können Sie es dann nur noch über VBA. Am interessantesten aber ist der über acDialog festgelegte Dialog-Modus. In diesem zeigt sich das Formular auf den ersten Blick in normalem Gewand. Tatsächlich aber ist es modal, was bedeutet, dass der Rest der Access-Anwendung gesperrt ist. Nur das geöffnete Dialogformular lässt sich bearbeiten. Zudem stoppt auch VBA nach dem Ausführen der aufrufenden Code-Zeile. Erst nach dem Schließen fährt es mit den weiteren Zeilen der Prozedur fort. Man kann sich dies etwa zunutze machen, um Eingaben im Formular auszulesen. Denn auch dann, wenn das Formular über die Visible-Eigenschaft im Formular-Code unsichtbar gemacht wird, übergibt VBA die Kontrolle an die aufrufende Prozedur. Nun könnte diese etwa Felder des Formulars auslesen, da es inzwischen zwar noch existiert, aber nicht mehr sichtbar ist. Das bedeutet allerdings auch, dass die Routine selbst das Formular über eine Close-Anweisung schließt, denn sonst irrt es auf Ewigkeiten im Speicher umher.

Als letzten Parameter finden Sie für OpenArgs im Listing den String "TEST1". Hier können Sie beliebige Daten, also auch Zahlenvariablen oder Objekte einsetzen. Das hat auf die Gestalt des geladenen Formulars keinen Einfluss. Über dessen Eigenschaft OpenArgs kann aber an beliebiger Stelle im Formular-Code auf diese Angabe Bezug genommen werden. So etwa im Beim Laden-Ereignis des Formulars:

Sub Form_Load()

     Msgbox Me.OpenArgs

End Sub

Hier würde TEST1 in einem Meldungsfenster erscheinen, sobald das Formular gestartet wurde.

Die Parameter für die Anweisung OpenReport zum Laden eines Berichts gleichen jenen von OpenForm. Hier ist zusätzlich die Ansichtsart acViewReport (Berichtsansicht) möglich. Ansonsten lassen sich hier ebenfalls Filter setzen, der WindowMode einstellen und OpenArgs übergeben. Es ist jedoch eine Besonderheit zu beachten: acViewNormal öffnet den Bericht nicht etwa in der normalen Ansicht, sondern schickt ihn zum Drucker! Wenn Sie also bei OpenReport lediglich den Namen des Berichts angeben und auf weitere Parameter verzichten, so wundern Sie sich nicht, dass scheinbar nichts passiert! Erst im Taskbar von Windows stellen Sie dann fest, dass ein Drucker in Aktion gesetzt wurde. Für die normale Ansicht unter Access setzten Sie daher acViewPreview ein.

Über VBA mit DoCmd geöffnete Objekte schließen Sie mit einer weiteren DoCmd-Anweisung:

DoCmd.Close acForm, "frmAdressen"

DoCmd.Close acModule, "mdlDoCommands"

DoCmd.Close acQuery, "qryAdressenG"

Formular- und

Datensatzsteuerung

Ist ein Formular erst über OpenForm geöffnet, dann können Sie es über zahlreiche DoCmd-Methoden steuern. Oder genauer gesagt: dessen Datensätze steuern.

Listing 2 zeigt eine gekürzte Version der Prozedur, welche Sie in der Beispieldatenbank finden. In der Originalversion ist nach jeder DoCmd-Zeile eine Msgbox eingebaut, die ausgibt, was gerade vonstattenging. Ohne diese Meldungsfenster würde der Code der Prozedur ja in Sekundenbruchteilen durchlaufen sein, ohne dass Sie die Auswirkungen der Anweisungen begutachten könnten.

Sub TestFormObject()

     DoCmd.OpenForm "frmAdressen"

     DoEvents

     DoCmd.SelectObject acForm, "frmAdressen"

     DoCmd.ApplyFilter , "Nachname LIKE 'Wag*'"

' DoCmd.SetFilter , "Nachname LIKE 'Wag*'","

     DoCmd.GoToRecord acDataForm, "frmAdressen", acLast

     DoCmd.FindRecord "Gudrun", acEntire, False, acSearchAll, False, acAll, True

     DoCmd.SetOrderBy "Vorname", "sfmKinder"

     DoCmd.FindRecord "Gisela", acEntire, False, acSearchAll, False, acAll, True

     DoCmd.FindNext

     DoCmd.SetProperty "txtNachname", acPropertyForeColor, RGB(64, 64, 255)

     DoCmd.Requery "txtVorname"

     DoCmd.ShowAllRecords

     DoCmd.Echo False

     DoCmd.GoToRecord acDataForm, "frmAdressen", acLast

     DoCmd.GoToRecord acDataForm, "frmAdressen", acFirst

     DoCmd.Echo True

     DoCmd.SearchForRecord acDataForm, "frmAdressen", acFirst, "Nachname='Hückmann'"

     If MsgBox("Formular schließen?", vbYesNo) = vbYes Then

         DoCmd.Save acForm, "frmAdressen"

         DoCmd.Close acForm, "frmAdressen", acSaveYes

     End If

End Sub

Listing 2: DoCmd-Anweisungen für verschiedene datensatzbezogene Aktionen

SelectObject setzte den Fokus auf ein Access-Objekt und/oder markiert dieses. In unserem Fall handelt es sich um das Formular frmAdressen. Sinn der Angelegenheit ist es, das entsprechende Objekt zu aktivieren. Denn die folgenden Anweisungen wirken immer auf das geöffnete aktive Objekt. Sind etwa mehrere Formulare gleichzeitig geöffnet, so steuern Sie mit diesem Befehl, welches den Fokus bekommen soll.

Nach dem Aktivieren kann per ApplyFilter eine Filterbedingung auf die angezeigten Datensätze angewandt werden. Das entspricht dem Vorgang, wenn Sie manuell über das Menüband oder über einen Spaltenkopf in Datenblattansicht einen Filter bestimmen. Hier werden nur jene Datensätze angezeigt, die im Nachnamefeld mit Wag beginnen. In der Navigationsleiste wird das deutlich, weil sich hier die Zahl der Datensätze verringert hat und vom Ausdruck (Gefiltert) begleitet wird. Statt ApplyFilter können Sie auch die Anweisung SetFilter mit gleicher Syntax benutzen. Der Unterschied besteht darin, dass beim Schließen des Formulars und gleichzeitigem Speichern der Filterausdruck dann in der Eigenschaft Filter verewigt bleibt.

Einen gesetzten Filter entfernen Sie einfach wieder mit einem Aufruf von DoCmd.ShowAllRecords.

GotoRecord erlaubt das Springen zu einem bestimmten Datensatz. Hier kann dezidiert angegeben werden, welches Formular zu steuern ist. Für den letzten Parameter gibt es verschiedene Steuerkonstanten. acLast springt zum letzten Datensatz, acFirst zum ersten, und so weiter. Interessanter ist da schon acGoto. In diesem Fall muss noch ein weiterer Parameter angehängt werden, der den Offset zum aktuellen Datensatz angibt. Möchten Sie etwa zum genau fünften Datensatz des Formulars springen, so verwenden Sie zwei Zeilen:

DoCmd.GoToRecord , , acFirst

DoCmd.GoToRecord , , acGoto, 4

GotoRecord wirkt nicht nur auf Formulare. Auch Tabellen oder Abfragen in Datenblattansicht, wie auch Berichte lassen sich damit steuern.

FindRecord spiegelt den Suchen-Dialog von Access wieder und weist deshalb genauso viele Parameter auf, wie jener an Einstellmöglichkeiten anbietet. Bild 1 zeigt die Analogie zwischen Dialog und möglichen Parametern. Diese Funktion ist durchaus mächtig. Wollten Sie sie durch eine andere VBA-Programmierung ersetzen, so käme dabei eine ziemlich umfangreiche Routine heraus, die allerlei Operationen rund um das Formular-Recordset enthielte. Vor allem aber ist sie unabhängig vom Objekt, das den Fokus besitzt. Die eine gleiche DoCmd-Zeile lässt sich auf verschiedene Formulare, Berichte oder Datenblätter anwenden.

Der Suchen-Dialog mit der FindRecord-Analogie und deren den Parametern

Bild 1: Der Suchen-Dialog mit der FindRecord-Analogie und deren den Parametern

Möchten Sie weitere Vorkommen des Suchausdrucks finden, so muss die ganze Zeile nicht erneut aufgerufen werden, Stattdessen setzen Sie einfach ein folgendes DoCmd.FindNext ein.

Eine Alternative zu FIndRecord ist das SQL-nähere SearchForRecord. Als Parameter geben Sie den Objekttyp und den Objektnamen an. Dann noch, ob nach dem ersten Vorkommen (acFirst) oder nach einem weiteren (acNext) oder früheren (acPrevious) gesucht werden soll. Daran schließt sich der Suchausdruck an, der der Syntax für eine WhereCondition (Filter) entspricht. Im Gegensatz zu FindRecord sind Sie hier also nicht auf einen einfachen Feldwert beschränkt, sondern können mehrere Kriterien festlegen und zusammensetzen!

Ähnlich, wie für das Filtern, gibt es auch eine DoCmd-Anweisung für das Sortieren von Datensätzen. SetOrderBy erwartet als Parameter den Namen des Felds, nach dem sortiert werden soll, und optional den Namen des Formulars oder Datenblatts – selbst Unterformulare sind möglich! Ohne diese Angabe wird das aktuelle Hauptobjekt sortiert. Sie können die Sortierreihenfolge festlegen, indem Sie an das gewünschte Feld noch den Ausdruck ASC (Aufsteigend) oder DESC (Absteigend) anhängen:

DoCmd.SetOrderBy "Vorname DESC"

Damit entspricht die Anweisung dem Setzen einer Kombination der Formulareigenschaften OrderBy und OrderByOn.

Die Formatierung von Feldern eines Datenblatts oder auch Formulars nehmen Sie in der Regel über den entsprechenden Abschnitt des Ribbon vor. Doch selbst dies lässt sich in VBA über den DoCmd-Befehl SetProperty erledigen. Dazu geben Sie den Namen des Steuerelements, welches formatiert werden soll, als Parameter an. Was formatiert werden soll, legen Sie mit einer der acProperty-Konstanten fest. Die Schriftfarbe etwa entspricht der Konstanten acPropertyForeColor. Weitere Angaben zu den Konstanten finden Sie in der Access-Hilfe zu SetProperty. Der letzte Parameter enthält schließlich den Wert für die Eigenschaft. Für Farben wäre dies ein RGB-Wert, für JA/NEIN-Eigenschaften entweder -1 oder 0. Im Beispiel wird die Schrift des Felds txtNachname blau eingefärbt (Bild 2).

Das Adressformular der Beispieldatenbank nach dem Setzen einer Formatierung auf das Feld Nachname über die Anweisung DoCmd.SetProperty

Bild 2: Das Adressformular der Beispieldatenbank nach dem Setzen einer Formatierung auf das Feld Nachname über die Anweisung DoCmd.SetProperty

Manchmal kommt es vor, dass sich die einem Formular zugrundeliegende Datenherkunft durch DAO-Operationen verändert hat. Nicht immer geben die Textfelder diese Änderung gleich wieder. Absichern können Sie das aber, indem Sie die Methode DoCmd.Requery aufrufen. Sie können ihr den Namen eines Felds als Parameter mitgeben. Nur dieses wird dann aktualisiert. Ohne Angabe werden alle Felder auf den neuesten Stand gebracht.

Die DoCmd-Operationen verhalten sich genauso, wie die analogen manuell angestoßenen. Springen Sie per GotoRecord etwa zum ersten Datensatz des Formulars und dann zu einem bestimmten Offset, so vollzieht sich das auch unmittelbar in der Anzeige. Das sieht nicht schön aus und kostet zudem Performance. Verhindern können Sie das mit der DoCmd-Anweisung Echo. Wird ihr als Parameter ein False übergeben, so friert die Oberfläche von Access ein. Dennoch werden alle VBA-Operationen weiter ausgeführt. Mit einem True wird der Zustand aufgehoben. Sie simulieren damit eine blitzschnelle Aktion. Tragen Sie allerdings dafür Sorge, dass das Echo auch im Falle von VBA-Fehlern unbedingt wieder eingeschaltet wird (Fehlerbehandlung). Sonst reagiert Access in der Folge weder auf Maus-, noch Tastaturbefehle!

Fensteranweisungen

In Listing 3 wird zunächst ein Formular geöffnet und dann mit SelectObject aktiviert. Denn die folgenden Anweisungen wirken grundsätzlich auf eben das in der Oberfläche aktive Objekt – namentlich kann es bei diesen nicht angegeben werden. Maximize maximiert das Formular nun, falls es nicht im Dialogmodus geladen ist. Das Gleiche gilt für Minimize zum Minimieren und Restore zum Wiederherstellen aus maximiertem oder minimiertem Zustand. Außerdem hängt das Ergebnis davon ab, ob es sich um ein normales Formular oder ein Popup-Formular handelt. Bei Ersteren wird es innerhalb der MDI-Arbeitsfläche von Access maximiert oder minimiert, bei Letzteren führt Maximize dazu, dass es den kompletten Bildschirm einnimmt und Minimize zum Verkleinern auf den Desktop. Die Anweisungen lassen sich genauso auf Datenblätter von Tabellen oder Abfragen anwenden, wie auch auf Berichte.

Sub TestWindowActions()

     DoCmd.OpenForm "frmAdressen"

     DoCmd.SelectObject acForm, "frmAdressen"

     DoCmd.MoveSize 0, 0, 8000, 6000

     DoCmd.Maximize

     DoCmd.Minimize

     DoCmd.Restore

     DoCmd.Hourglass True

     DoCmd.Hourglass False

     If MsgBox("Access beenden?", vbYesNo) = vbYes Then

         DoCmd.Quit acQuitSaveAll

     End If

End Sub

Listing 3: Fensterbezogene Aktionen mit DoCmd

DoCmd.Hourglass lässt die Windows-Sanduhr anzeigen, falls als Parameter ein True übergeben wird. Ein False schaltet sie aus und stellt den normalen Mauszeiger wieder her. Das ist immer dann sinnvoll, wenn Sie im Hintergrund eine länger dauernde VBA-Routine abarbeiten lassen, die den Benutzer ins Grübeln bringen könnte, weil Access nun scheinbar nicht mehr reagiert.

Die Datenbank und Access beenden können Sie mit der Anweisung Quit. Sie schließt automatisch alle noch geöffneten Objekte und speichert gegebenenfalls deren Zustand, so der optionale Parameter auf acQuitSaveAll steht. acQuitSaveNone schlösse sie hingegen ohne Abspeichern. Danach beendet sich auch Access selbst.

Objektoperationen

Das Gegenstück zum Öffnen eines Objekts per DoCmd.Open... ist das Schließen über DoCmd.Close. Hier gibt es nicht für jede Objektart eine gesonderte Anweisung. Vielmehr wird die Objektart als erster Parameter angegeben und darauf folgt der Objektname.

Die erste Zeile in Listing 4 testet zuerst über die IsLoaded-Funktion der AllForms-Auflistung, ob das Formular frmAdressen gerade geöffnet ist. Nur dann wird die folgende Close-Anweisung abgesetzt. Andernfalls käme es eventuell zu einer Fehlermeldung.

Sub TestCopyDeleteObject()

     If CurrentProject.AllForms("frmAdressen").IsLoaded Then

         DoCmd.Close acForm, "frmAdressen"

     End If

     DoCmd.CopyObject , "frmAdressen2", acForm, "frmAdressen"

     DoCmd.SelectObject acForm, "frmAdressen2", True

     DoCmd.Rename "frmAdressen3", acForm, "frmAdressen2"

     DoCmd.DeleteObject acForm, "frmAdressen3"

End Sub

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!