Tipps und Tricks

In dieser Reihe unserer Tipps und Tricks rund um Access und VBA erfahren Sie, wie Sie mit einer einfachen VBA-Funktion blitzschnell Verzeichnisse erstellen. Außerdem lernen Sie eine kleine VBA-Prozedur kennen, mit der Sie Texte mithilfe von Google von Deutsch nach Englisch übersetzen können. Haben Sie auch noch einen coolen Tipp für uns Immer her damit – einfach an info@access-im-unternehmen.de.

Verzeichnisse erstellen

Mal eben schnell per VBA ein Verzeichnis erstellen Kein Problem: Sofern nur eine Verzeichnisebene zu erstellen ist und die darunter liegenden Ebenen bereits vorhanden sind, brauchen Sie dazu nur den MkDir-Befehl mit entsprechenden Parametern abzusetzen.

Wenn es jedoch mehrere Verzeichnis-ebenen sein sollen und Sie noch nicht einmal wissen, ob eine oder mehrere Ebenen bereits existieren, kommt die Funktion aus Listing 1 genau richtig. Voraussetzung ist, dass es sich um ein Verzeichnis mit Angabe des Laufwerkbuchstabens handelt, also etwa c:\\Test.

Public Function CreateDir(strDir) As Boolean
     Dim strDirTemp As String
     Dim intPosStart As Integer
     intPosStart = InStr(4, strDir, "\\")
     If Not Right(Trim(strDir), 1) = "\\" Then
         strDir = strDir & "\\"
     End If
     Do While Not intPosStart = 0
         On Error Resume Next
         MkDir Mid(strDir, 1, intPosStart)
         On Error GoTo 0
         intPosStart = InStr(intPosStart + 1, strDir, "\\")
     Loop
     CreateDir = Len(Dir(strDir, vbDirectory)) > 0
End Function

Listing 1: Erstellen eines Verzeichnisses per VBA-Funktion

Die Funktion rufen Sie beispielsweise mit dem folgenden Befehl auf, wobei Sie das Ergebnis sowohl im Direktbereich ausgeben (wie in diesem Fall) oder auch im Code weiterverarbeiten können:

  CreateDir ("c:\\test1\\test2\\test3")
Wahr

Die Funktion ermittelt den Beginn der eigentlichen Verzeichnisse und speichert die Position des ersten Backslash in der Integer-Variablen intPosStart. Außerdem prüft sie, ob der angegebene Ausdruck mit einem Backslash endet.

Dies ist nötig, damit auch das hinterste Verzeichnis angelegt wird. Sollte der Backslash fehlen, ergänzt die Funktion diesen noch.

Nach den Vorbereitungsarbeiten durchläuft die Funktion so lange eine Do While-Schleife, bis die Variable intPosStart den Wert 0 enthält. Die Prozedur legt nun mit der MkDir-Methode das Verzeichnis an, das dem Inhalt von strDir bis zu der in intPosStart gespeicherten Position entspricht – im ersten Durchlauf also etwa c:\\test1\\. Sollte das Verzeichnis bereits vorhanden sein, führt dies zu einem Fehler – was aber nicht weiter schlimm ist, denn wir haben die Fehlerbehandlung mit der On Error Resume Next-Anweisung während der Ausführung von MkDir deaktiviert. Ist das Verzeichnis noch nicht vorhanden, legt die Funktion dieses an.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

In dieser Folge unserer Tipps und Tricks erfahren Sie, wie Sie Datensätze zweier Tabellen in einer einzigen Abfrage zusammenführen, wie Sie Berichte mehrfach drucken und wie Sie die Daten in Haupt- und Unterformular synchron anzeigen – so, dass das Hauptformular jeweils den im Unterformular markierten Datensatz anzeigt und umgekehrt.

Daten zusammenführen per Abfrage

Manchmal geschehen beim Entwickeln ungeplante Dinge. So kann es beispielsweise geschehen, dass Sie zwei Versionen einer Datenbank besitzen – zum Beispiel eine veraltete, archivierte Version und eine aktuelle. Wenn Sie dann durch Zufall (etwa durch versehentliches Öffnen der älteren Version) die alte Version weiterentwickeln, aber in der anderen die Daten pflegen, können Sie am einfachsten die aktuellen Daten in die weiterentwickelte Version übernehmen.

Sie könnten dann natürlich schnell alle Datensätze löschen und mit den Daten der neuen Tabelle füllen oder die komplette Tabelle löschen und neu anlegen. Beides führt zu Problemen: Beim Neuerstellen der Datensätze stimmen Beziehungen nicht mehr oder die Beziehungen müssen gar für eine komplett neu angelegte Tabelle neu aufgebaut werden.

Einfacher ist die folgende Methode, die in zwei Schritten nicht mehr vorhandene Datensätze der alten Version entfernt und die vorhandenen Datensätze aktualisiert.

Das Beispiel bezieht sich auf die Tabellen tblArtikel und tblArtikel_Geaendert, wobei tblArtikel den alten Datenbestand repräsentiert und tblArtikel_Geaendert den neuen, geänderten Datenbestand. Dabei gibt es gelöschte, geänderte und neu angelegte Datensätze.

Die Tabelle tblArtikel_Geaendert können Sie dabei in die Zieldatenbank kopieren oder einfach nur eine Verknüpfung erstellen – wir haben diese einfach kopiert.

Zunächst kümmern wir uns darum, die in der Tabelle tblArtikel_Geaendert gelöschten Datensätze auch aus der Tabelle tblArtikel zu löschen.

Das Entfernen der Datensätze aus der Tabelle tblArtikel, die zwischenzeitlich aus der Tabelle tblArtikel_Geaendert gelöscht wurden, übernimmt die Aktionsabfrage aus Abb. 1. Diese enthält die Tabelle tblArtikel als Datenherkunft. Um alle Artikel dieser Tabelle zu ermitteln, die nicht mehr in der Tabelle tblArtikel_Geaendert vorhanden sind, verwenden wir eine Unterabfrage. Diese lautet SELECT ArtikelID FROM tblArtikel_Geaendert und liefert alle noch vorhandenen Datensätze. Das Feld ArtikelID eines jeden Datensatzes der Tabelle tblArtikel wird nun mit den ermittelten Werten verglichen. Ist der Wert nicht vorhanden, ist die Bedingung erfüllt und der Datensatz kann gelöscht werden.

pic001.png

Abb. 1: Löschen der nicht mehr vorhandenen Datensätze

Danach werfen wir einen Blick auf die geänderten und neu hinzugefügten Datensätze. Genau genommen gehen wir dabei nicht sonderlich differenziert vor, sondern gleichen einfach die kompletten Daten ab. Der Clou liegt hierbei darin, beide Vorgänge in einem Rutsch zu erledigen, sprich: mit einer einzigen UPDATE-Abfrage und ohne INSERT INTO-Abfrage.

Dazu erstellen Sie eine neue, leere Abfrage und ziehen die Ziel- und die Quelltabelle in die Entwurfsansicht. Damit jeder Datensatz mit seinem Pendant abgeglichen wird, erstellen Sie eine Beziehung zwischen den Feldern ArtikelID der beiden Tabellen tblArtikel und tblArtikel_Geaendert. Damit liefert das Abfrageergebnis aber nur solche Artikel, bei denen die ArtikelID in beiden Tabellen vorkommt. Wir wollen jedoch auch die Artikel im Ergebnis der Abfrage sehen, die zwar in der Tabelle tblArtikel_Geaendert enthalten sind, aber nicht in der Tabelle tblArtikel – also alle Artikel, die neu hinzugekommen sind.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Diesmal gibt es drei Tipps rund um die Arbeit mit Microsoft Access – die haben es dafür aber auch in sich. Haben Sie sich auch schon mal geärgert, dass Sie ein Nachschlagefeld für ein Fremdschlüsselfeld in der Tabelle definiert haben und dann nur noch die verknüpften Daten, aber nicht mehr die enthaltenen Werte in der Tabelle vorgefunden haben Dann hilft Ihnen der erste Trick weiter, mit dem Sie diese Daten ohne änderung des Tabellenentwurfs wieder hervorzaubern. Der zweite Tipp dreht sich um das Hinzufügen von langen Texten zu Memofeldern. Dies gelingt in Formularen nur bis zu einer bestimmten Anzahl Zeichen. Wollen Sie trotzdem längere Texte einfügen, gehen Sie den hier beschriebenen Umweg über eine Textdatei. Im dritten Tipp erfahren Sie schließlich, wie Sie das VBA-Projekt der aktuellen Access-Datei referenzieren können.

Werte von Nachschlagefeldern anzeigen

Wenn Sie die Fremdschlüsselfelder Ihrer Tabellen gleich beim Erstellen als Nachschlagefelder definieren, sparen Sie eine Menge Arbeit: Erstens hilft der entsprechende Assistent schnell und zuverlässig, das Nachschlagefeld und auch die Beziehung zwischen den beteiligten Tabellen einzurichten. Und zweitens brauchen Sie solche Felder nur noch einfach in den Entwurf eines Formulars zu ziehen, um gleich ein praktisches Kombinationsfeld zur Auswahl der Daten der verknüpften Tabelle vorzufinden.

Dummerweise erschweren Nachschlagefelder das Analysieren der Tabelleninhalte, wenn beispielsweise Daten einmal nicht so angelegt wurden, wie Sie es sich wünschten. Ein direkter Blick auf die in den Feldern gespeicherten Zahlenwerte statt der Anzeigewerte wie etwa Kategorien oder Lieferanten einer Artikeltabelle wäre hilfreich.

Es ist jedoch kein Problem, eine solche Sicht herzustellen – und das ohne Anpassung des Entwurfs der betroffenen Tabelle. Sie brauchen einfach nur eine Abfrage auf Basis der Tabelle zu erstellen und für die Nachschlagefelder die Eigenschaft Steuerelement anzeigen auf Textfeld zu ändern (siehe Abb. 1).

pic001.png

Abb. 1: Nachträgliches Deaktivieren eines Nachschlagefeldes

Schon zeigt die Abfrage die tatsächlichen Werte der Fremdschlüsselfelder statt der Werte der verknüpften Felder an (s. Abb. 2).

pic003.png

Abb. 3: Lange Texte lassen sich ab einer bestimmten Zeichenzahl nicht mehr in ein Memofeld kopieren.

Große Texte in Memofelder einlesen

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

In dieser Ausgabe gibt es mal wieder ein paar Tipps und Tricks rund um die Arbeit mit Microsoft Access. Im ersten Tipp erfahren Sie, wie Sie Unterberichte in einem Bericht wahlweise ein- oder ausblenden. Der zweite Tipp verrät, wie Sie die Zusammenstellung von SQL-Ausdrücken per VBA vereinfachen. Und schließlich zeigen wir Ihnen, wie Sie XML-Dokumente auf ihre Gültigkeit hin prüfen können.

Unterberichte nach Bedarf

Unterberichte kommen immer dann zum Einsatz, wenn ein Bericht Daten aus mehreren Tabellen gleichzeitig anzeigen soll, die nicht alle hierarchisch miteinander verknüpft sind. Wenn Sie zum Beispiel alle Ansprechpartner und alle Projekte zu einem Kunden in einem Bericht anzeigen möchten, erledigen Sie dies am besten mit zwei entsprechenden Unterberichten.

Manchmal möchten Sie den Bericht aber vielleicht nicht mit allen enthaltenen Unterberichten ausgeben – etwa, weil einer der Unterberichte Informationen enthält, die Sie gerade nicht benötigen.

In diesem Fall brauchen Sie zwei Dinge: Ein Formular, mit dem Sie die gewünschten Unterberichte selektieren, und einen Bericht, der die Unterberichte entsprechend dieser Auswahl ein- oder ausblendet.

Der Bericht dieses Beispiels soll drei Unterberichte enthalten, die vor dem Öffnen über ein Formular namens frmUnterberichte aktiviert oder deaktiviert werden sollen. Dieses Formular sieht im Entwurf wie in Abb. 1 aus. Die Kontrollkästchen heißen chk1, chk2 und chk3, die Schaltfläche cmdBericht. Ein Klick auf die Schaltfläche löst die folgende Ereignisprozedur aus, die schlicht den Bericht in der Seitenansicht öffnet:

pic001.png

Abb. 1: Das Formular zum Aktivieren und Deaktivieren der Unterberichte

Private Sub cmdBericht_Click()
    DoCmd.OpenReport "rpt", acViewPreview
End Sub

Die Unterberichte namens srp1, srp2 und srp3 sind zu Beispielzwecken recht schlicht aufgebaut und enthalten jeweils nur ein Bezeichnungsfeld (s. Abb. 2).

pic003.png

Abb. 2: Einer der drei Unterberichte

Der Hauptbericht heißt rptBericht und sieht im Entwurf wie in Abb. 3 aus. Dort sehen Sie drei Textfelder, welche die Überschriften der Unterberichte darstellen, dazwischen haben wir die Unterberichte eingefügt.

pic004.png

Abb. 3: Der Hauptbericht mit den drei Unterberichten

Wichtig ist, dass Sie die Textfelder und die Unterberichte direkt untereinander einfügen. Wenn Sie anderenfalls zwischen jedem Steuerelement etwa einen halben Zentimeter Platz lassen und dann den mittleren Bericht ausblenden, entsteht eine unschöne Lücke.

Wenn Sie nun in die Seitenansicht wechseln, sieht der Bericht wie in Abb. 4 aus – alle Überschriften und Unterberichte werden unmittelbar untereinander angezeigt.

pic002.png

Abb. 4: Berichtsvorschau der Unterberichte

Genau genommen können Sie die Überschriften auch in die Unterberichte integrieren und stattdessen einfach leere Textfelder zwischen den Berichten platzieren. Die Hauptaufgabe der Textfelder ist nämlich die eines Platzhalters zwischen den Berichten.

Wie nun blenden wir die einzelnen Berichtsbereiche aus Die notwendigen Informationen hält ja das Formular frmUnterberichte bereit. Der Bericht muss diese also beim Öffnen selbst auswerten, was wie in der folgenden Prozedur geschieht:

Private Sub Detailbereich_Format(Cancel As Integer, FormatCount As Integer)
    With Forms!frmUnterberichte
        Me!txt1.Visible = !chk1
        Me!srp1.Visible = !chk1
        Me!txt2.Visible = !chk2
        Me!srp2.Visible = !chk2
        Me!txt3.Visible = !chk3
        Me!srp3.Visible = !chk3
    End With
End Sub

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Wollten Sie schon immer mal einen Seitenfuß nur auf der letzten Berichtsseite anzeigen Oder dem Benutzer die Möglichkeit geben, Steuerelemente auf Formularen einfach per Tastenkombination zu betätigen Und kennen Sie schon den Trick, wie Sie ein Bezeichnungsfeld über die Entwurfsansicht von Formularen an ein anderes Steuerelement anhängen können Und vielleicht interessiert Sie auch, wie das per VBA geschieht Und wie funktioniert überhaupt die Z-Reihenfolge von Steuerelementen und warum scheint diese manchmal zu spinnen Nun, irgendeiner dieser oder der anderen in diesem Beitrag enthaltenen Tricks wird Sie schon begeistern. Lesen Sie einfach weiter!

Seitenfuß nur auf letzter Seite

Der große Unterschied zwischen dem Seitenfuß und dem Berichtsfuß in der Seitenansicht von Berichten ist, dass der Seitenfuß immer ganz unten landet und der Berichtsfuß direkt hinter den letzten Detail- oder Gruppenfußbereichen.

Wer im Fuß der letzten Seite Informationen unterbringen möchte, und nur dort, der wird um den Einsatz des Seitenfuß-Bereichs also nicht herumkommen.

Es gibt mehrere Varianten, dafür zu sorgen, dass bestimmte Informationen des Seitenfußbereichs nur auf der letzten Seite angezeigt werden. Welche Sie wählen, hängt davon ab, ob der Seitenfußbereich auch auf den anderen Seiten Informationen anzeigen soll.

Ist dies nicht der Fall, verwenden Sie eine Lösung, bei der Sie den Seitenfuß einfach auf allen Seiten außer auf der letzten Seite ausblenden.

Generell blenden Sie einen Bereich ganz einfach aus, indem Sie eine Ereignisprozedur für die Ereigniseigenschaft Beim Formatieren anlegen und dort den Parameter Cancel auf False einstellen – so bleibt der Seitenfuß unsichtbar:

Private Sub Seitenfußbereich_Format(Cancel As
 Integer, FormatCount As Integer)
    Cancel = True
    End Sub

Dieses Ereignis wird für jeden Seitenfußbereich einmal aufgerufen, also auch für jede Seite einmal. Aktuell wird der Seitenfuß aber auf jeder Seite ausgeblendet, auch auf der letzten. Sie müssen also noch herausfinden, ob das Ereignis für den Seitenfuß der letzten oder einer anderen Seite ausgelöst wird. Dazu legen Sie zunächst ein einfaches Textfeld mit der Bezeichnung txtSeiten und dem Steuerelementinhalt =Pages an.

Dieses Steuerelement zeigt nun im Seitenfuß jeweils die Gesamtseitenzahl des Berichts an. Damit lässt sich etwas anfangen, denn diese Information erhalten Sie auch via VBA – genauso wie die Nummer der aktuellen Seite.

Sie brauchen also nur noch zu prüfen, ob die aktuelle Seite der Seitenzahl entspricht, und genau dann den Fußbereich einzublenden. Und das geht so:

Private Sub Seitenfußbereich_Format(Cancel
 As Integer, FormatCount As Integer)
    Cancel = Not (Me.Page = Me.Pages)
    End Sub

Sie mögen nun berechtigterweise fragen, warum wir ein Textfeld namens txtSeiten anlegen, um die Seitenzahl anzuzeigen, wenn wir doch per VBA die Seitenzahl ermitteln Ganz einfach: Pages liefert nur dann die richtige Seitenzahl, wenn diese zuvor berechnet wurde – und das geschieht nur durch das Hinzufügen eines Steuerelements mit dem Steuerelementinhalt =Pages. Anderenfalls liefert Me.Pages immer den Wert 0.

Wenn Sie den Seitenfuß auch auf den übrigen Seiten verwenden möchten, um Informationen wie etwa die Seitenzahl anzuzeigen, und nur auf der letzten Seite sollen weitere Informationen erscheinen, haben Sie noch leichteres Spiel: Sie brauchen dann nur die Sichtbarkeit der entsprechenden Steuerelemente über die oben genannte Bedingung einzustellen, also etwa so:

Me.txtDatum.Visible = Me.Page = Me.Pages

Steuerelemente direkt per Tastatur ansprechen

Vielleicht haben Sie dies schon einmal bei anderen Anwendungen gesehen und sich gefragt, wie Sie das auch in Access-Formularen hinbekommen: Da findet man Schaltflächen und ähnliche Steuerelemente, bei denen ein bestimmter Buchstabe unterstrichen ist.

Wenn Sie den Buchstaben dann bei gedrückter Alt-Taste drücken, aktiviert oder betätigt Access das betroffene Steuerelement.

Bei einer Schaltfläche ist dies ganz einfach: Hier brauchen Sie nur die Beschriftung anzupassen, indem Sie vor das Zeichen, das unterstrichen dargestellt werden soll, ein Kaufmanns-Und (&) setzen – schon können Sie diese Schaltfläche per Tastatur steuern (s. Abb. 1).

pic003.png

Abb. 1: Verschiedene Beispiele für Steuerelemente, die Sie per Tastenkombination ausführen oder aktivieren können

Bei Beschriftungsfeldern von Steuerelementen gelingt dies ebenso schnell. Sie müssen nur beachten, dass Sie nicht das eigentliche Steuerelement, sondern das Beschriftungsfeld anpassen.

Dies aktiviert jeweils das mit dem Bezeichnungsfeld verknüpfte Steuerelement. Aufpassen müssen Sie, wenn Sie das Bezeichnungsfeld etwa eines Textfelds einmal ausgeschnitten und woanders eingefügt haben, um beispielsweise Spaltenüberschriften in einem Endlosformular zu erzeugen.

Dann sind Bezeichnungsfeld und Textfeld nicht mehr miteinander verknüpft und das Ausführen der Tastenkombination führt nicht mehr zum Erfolg. Das Bezeichnungsfeld verfügt dann aber über ein eigenes Beim Klicken-Ereignis, das Sie mit einer entsprechenden Ereignisprozedur füllen könnten, das wiederum das betroffene Steuerelement aktiviert.

Leider funktioniert dies aber in der Praxis nicht: Zwar führt ein Klick auf ein so ausgestattetes Bezeichnungsfeld tatsächlich zum Aktivieren des Steuerelements, aber die Tastenkombination hilft nicht weiter.

Die Beispiele zu diesem Tipp finden Sie im Formular frmSteuerelementPerTastatur der Beispieldatenbank.

Gebundene und ungebundene Bezeichnungsfelder

Es gibt nur eine Art von Bezeichnungsfeldern. Oder etwa doch nicht Wenn wir die Bezeichnungsfelder, die automatisch mit anderen Steuerelementen wie Text-, Kombinations- oder Listenfeldern zum Formular hinzugefügt werden, mit denen vergleichen, die als eigenes Steuerelement im Formular oder Bericht landen, stellen wir zumindest einen großen Unterschied fest: Die allein stehenden Bezeichnungsfelder verfügen über fünf Ereigniseigenschaften, mit denen Sie beispielsweise einen Mausklick auf ein Bezeichnungsfeld abfangen können. Die gebundenen Bezeichnungsfelder besitzen gar keine Ereigniseigenschaften.

Desweiteren fehlen bei den gebundenen Bezeichnungsfeldern die beiden Eigenschaften Hyperlink-Adresse und Hyperlink-Unteradresse, und eine Kontextmenüleiste lässt sich auch nur bei ungebundenen Bezeichnungsfeldern über die gleichnamige Eigenschaft einstellen.

Dafür lassen sich gebundene Bezeichnungsfelder zusammen mit dem jeweiligen Steuerelement verschieben.

Wenn Sie einem gebundenen Bezeichnungsfeld eine Ereignisprozedur zuweisen möchten oder die übrigen beim gebundenen Bezeichnungsfeld fehlenden Eigenschaften nutzen möchten, erreichen Sie dies nur, wenn Sie die Bindung zwischen Bezeichnungsfeld und Steuerelement aufheben. Dies ist natürlich auch unbedingt nötig, wenn Sie das Bezeichnungsfeld als Spaltenüberschrift im Formularkopf und die eigentlichen Steuerelemente in der Endlosansicht im Detailbereich anzeigen möchten.

Wie aber heben Sie die Bindung auf Ganz einfach: Sie schneiden das Bezeichnungsfeld mit Strg + X oder dem entsprechenden Kontextmenübefehl aus und fügen es im gewünschten Bereich mit Strg + V wieder ein.

Die Beziehung zwischen Bezeichnungsfeld und dem zu beschriftenden Steuerelement können Sie nur wieder herstellen, wenn Sie das Bezeichnungsfeld erneut ausschneiden, das Zielsteuerelement markieren und das Bezeichnungsfeld dann einfügen.

Steuerelemente mit und ohne Bezeichnungsfelder

Wenn Sie ein Steuerelement wie ein Textfeld in ein Formular einfügen, fügt Access immer automatisch ein Bezeichnungsfeld hinzu. Wirklich immer Nein, Sie können diese Funktion auch deaktivieren.

Dazu öffnen Sie ein Formular in der Entwurfsansicht und klicken auf ein Steuerelement der Symbolleiste mit den Steuerelementen (Toolbox), zum Beispiel ein Textfeld. Fügen Sie das Textfeld aber noch nicht in das Formular ein!

Das Eigenschaftsfenster zeigt nun wie üblich die Eigenschaften des Steuerelements an. Aber auch nur anscheinend, denn es enthält auch einige Eigenschaften, die ein bereits angelegtes Textfeld-Steuerelement nicht aufweist.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Die Tipps-und-Tricks-Sammlung von Access im Unternehmen wird diesmal um das Verknüpfen von Tabellen per Code erweitert. Außerdem zeigen wir Ihnen, wie Sie Ereignisprozeduren vom Eigenschaftsfenster aus ganz schnell anlegen. Wer gern gelegentlich mit instabilen Datenbanken arbeitet, muss diese hin und wieder mal dekompilieren – das geht mit unserer Decompile-Datenbank per Doppelklick und lässt sich ganz schnell einrichten. Schließlich kümmern wir uns um das Verhalten von Textfeldern beim Erhalt des Fokus: Komplett markieren, zum Start oder ans Ende

Tabellen verknüpfen per Code

Eine Tabellenverknüpfung legen Sie normalerweise über den entsprechenden Menübefehl von Access an (unter Access 2007 zum Beispiel über den Ribbon-Eintrag Externe Daten|Access). Wenn Sie diese Aufgabe etwa beim Start der Frontenddatenbank automatisch ausführen lassen möchten, brauchen Sie ein paar Zeilen Code.

Am einfachsten geht dies mit dem VBA-Pendant zum Menübefehl, und zwar mit der TransferDatabase-Methode des DoCmd-Objekts:

DoCmd.TransferDatabase acLink, "Microsoft Access", "<Quelldatenbank>", acTable, "<Name der Verküpfung>", "<Name der Quelltabelle>"

Dies klappt in der Regel ganz gut, führt aber in Einzelfällen zu Unannehmlichkeiten, zum Beispiel beim Einsatz unter der Access 2007-Runtime und dort speziell bei Verwendung von Backenddatenbanken, die nicht auf dem gleichen Rechner wie das Frontend liegen. Dort erscheint nämlich die gleiche Hinweismeldung, die auch beim Öffnen von Datenbankdateien aus nicht vertrauenswürdigen Ordnern erscheint – und zwar bei jedem Aufruf der TransferDatabase-Methode.

Um dies zu umgehen, brauchen Sie ein paar Zeilen Code mehr:

Dim db As DAO.Database
Dim tdf As DAO.TableDef
Set db = CurrentDb
Set tdf = db.CreateTableDef("tblVersion", 0,
"tbl_VersionFE", ";DATABASE=z:\\ShopSoft.accdb")
db.TableDefs.Append tdf
db.TableDefs.Refresh
Set tdf = Nothing
Set db = Nothing

Die CreateTableDef-Methode schafft es, eine Verknüpfung ohne nervende Hinweismeldungen herzustellen. Die folgende Append-Methode fügt die noch im leeren Raum stehende Verknüpfung zur Auflistung TableDefs hinzu und die Refresh-Methode sorgt schließlich dafür, dass die Verknüpfung auch gleich im Datenbankfenster erscheint.

Ereignisprozedur per Mausklick

Wenn Sie eine Ereignisprozedur anlegen, geschieht dies normalerweise durch die folgenden Schritte:

  • Sie markieren das betroffene Element.
  • Sie zeigen das Eigenschaftsfenster an, sofern dieses noch nicht aktiviert ist.
  • Sie wählen die Registerseite Ereignis aus.
  • Dann wählen Sie entweder aus dem Kombinationsfeld den Eintrag [Ereignisprozedur] aus und klicken auf die Schaltfläche mit den drei Punkten oder Sie klicken direkt auf diese Schaltfläche und wählen aus dem nun erscheinenden Dialog den Eintrag Codegenerator aus (s. Abb. 1).
  • pic001.png

    Abb. 1: Auswahl eines Werkzeugs zum Füllen einer Ereigniseigenschaft

  • Schließlich landen Sie im VBA-Editor und können den dort bereits angelegten Prozedurrumpf füllen.

Es gibt mindestens zwei Alternativen zu dieser Vorgehensweise, die schneller sein können:

  • Sie öffnen den VBA-Editor direkt, öffnen das Klassenmodul des jeweiligen Formulars oder Berichts, wählen im Kombinationsfeld links oben im Codefenster den Namen des betroffenen Steuerelements und im rechten Kombinationsfeld die benötigte Ereignisprozedur aus.
  • Sie aktivieren eine spezielle Option von Access und brauchen dann beim Anlegen der Ereignisprozedur über das Eigenschaftsfenster nur noch auf die Schaltfläche mit den drei Punkten für die gewünschte Eigenschaft zu klicken.

Letztere Version dürfte die schnellste sein. Die Option, die Sie dazu einstellen müssen, heißt Immer Ereignisprozeduren verwenden.

Sie finden diese unter Access 2003 und älter im Optionen-Dialog (Extras|Optionen) im Bereich Formulare/Berichte und unter Access 2007 in den Access-Optionen im Bereich Objekt-Designer|Formulare/Berichte.

Folgende Nullen statt führender Nullen

Ein Kunde wollte mal IDs mit Nullen bis auf fünf Stellen aufgefüllt haben. Die Zahlen 1, 27, 392 und 4433 sollten also so aussehen: 10000, 27000, 39200, 44330. Falls Sie auch mal so etwas brauchen, können Sie dies natürlich per VBA lösen – im vorliegenden Fall sollte dieses Format aber einfach in einer Abfrage untergebracht werden. Natürlich kann man dort auch eine VBA-Funktion integrieren, aber das muss ja nicht sein.

Stattdessen verwenden wir die ganz selten genutzte StrReverse-Funktion, die eine Zeichenkette umdreht. Dies führt zwar nicht direkt zum Ziel, aber auf folgendem Umweg schon.

Sie drehen also zunächst die Zahlen mit folgender Funktion um:

StrReverse(Zahl)

Für die Zahl 392 ergibt dies 293. Jetzt kommt die üblicherweise zum Anfügen führender Nullen verwendete Format-Funktion ins Spiel. Wenn Sie einer Zahl so viele Nullen voranstellen möchten, bis diese fünf Stellen aufweist, geht dies etwa so:

Format(Zahl, "00000")

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

In der Rubrik Tipps und Tricks erhalten Sie diesmal aus Platzgründen nur zwei Problemlösungen. Sie erfahren, wie Sie die Menü- und Symbolleisten aus älteren Access-Versionen auch in Access 2007 hinüberretten, das ja bekanntlich die herkömmlichen Menüs durch das Ribbon ersetzt hat, und wie Sie das Primärschlüsselfeld von Tabellen und Abfragen ermitteln.

Menüs und Symbolleisten in Access 2007

Wer eine Datenbankdatei im Format von Access 2003 und älter erstellt hat, die Menü- und Symbolleisten verwendet, befürchtet für den Umstieg auf Access 2007 möglicherweise eine Menge Arbeit: Mit dieser Access-Version hat Microsoft ein neues Menüsystem namens Ribbon eingeführt.

Es gibt jedoch Hoffnung: Niemand muss unter Access 2007 auf seine gewohnten Menüs verzichten. Genau genommen funktionieren diese dort wie gewohnt, allein ihre Bearbeitung über den Anpassen-Dialog ist nicht mehr möglich.

Voraussetzung für die Verwendung von Menüs und Symbolleisten unter Access 2007 ist, dass Sie die Datenbank nicht in eine .accdb-Datei umwandeln, sondern im .mdb-Format belassen, und dass Sie noch unter Access 2003 eine kleine Einstellung vornehmen, die möglicherweise ohnehin bereits Bestand hat.

Diese Einstellung namens Eingebaute Symbolleisten zulassen finden Sie im Start-Dialog (Menüeintrag Extras|Start). Abb. 1 zeigt diesen Dialog, mit dem Sie übrigens auch die gewünschte Menü- und Symbolleiste festlegen müssen.

pic001.png

Abb. 1: Einstellen der Option zum Anzeigen benutzerdefinierter Menü- und Symbolleisten unter Access 2007

Das Ergebnis sieht schließlich wie in Abb. 2 aus: Access 2007 erkennt man nur noch am neuen Access-Symbol oben links. Das Ribbon ist verschwunden und Access zeigt die Menüleiste vergangener Versionen an.

pic002.png

Abb. 2: Eine Menüleiste in einer .mdb-Datenbank unter Access 2007

Primärschlüsselfeld einer Tabelle ermitteln

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

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.

pic001.tif

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:

pic002.tif

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

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

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.

Dateneingabe ohne Datensatzwechsel

Wenn Sie Detaildaten wie etwa einen Kunden, einen Artikel oder ähnliches eingeben, verwenden Sie in der Regel ein entsprechendes Formular, das nur zur Eingabe dieser Daten dient.

Beim Aufruf dieses Formulars geben Sie mit dem Parameter DataMode in der folgenden Anweisung direkt an, dass nun ein neuer Datensatz eingegeben werden soll:

DoCmd.OpenForm "Formularname", DataMode:=acFormAdd

Damit weiß das Formular, dass es direkt einen neuen, leeren Datensatz anzeigen und alle anderen Datensätze der Datenherkunft ausblenden soll.

Wenn Sie die Eigenschaften Trennlinie, Navigationsbereich und Datensatzmarkierer auf Nein einstellen, befreien Sie das Formular überdies von unnötigem Schnickschnack, den man beim Anlegen eines einfachen Datensatzes nicht braucht.

Der Benutzer kann hiermit keinen Unsinn mehr anstellen – es sei denn, er springt mit der Eingabe- oder Tabulator-Taste bis zum letzten Steuerelement in der Aktivierreihenfolge und darüber hinaus, dann gelangt er nämlich in einen neuen Datensatz.

Das können Sie allerdings leicht unterbinden: Stellen Sie dazu einfach die Eigenschaft Zyklus des Formulars auf den Wert Aktueller Datensatz ein. Der Fokus wechselt dann vom letzten Steuerelement der Aktivierreihenfolge zum ersten Steuerelement des Formulars.

DoCmd.OpenForm-Argumente funktionieren nicht

Während der Entwicklung von Formularen treten manchmal nicht nachvollziehbare Probleme auf.

So kann es zum Beispiel vorkommen, dass Sie ein Formular mit einer Anweisung wie der folgenden aufrufen, aber das mit dem Parameter OpenArgs übergebene Öffnungsargument einfach nicht beim Formular ankommt:

DoCmd.OpenForm "Formularname", OpenArgs:="Test"

Im Ereignis Beim Öffnen des Formulars möchten Sie das Öffnungsargument nun so auslesen:

Dim strOeffnungsargument As String
strOeffnungsargument = Me.OpenArgs

Es gibt jedoch die Fehlermeldung Laufzeitfehler 94: Unzulässige Verwendung von Null, OpenArgs ist also scheinbar leer.

Der durch das fehlende Öffnungsargument verursachte Fehler tritt immer dann auf, wenn das Formular bereits geöffnet ist – egal, ob sichtbar oder unsichtbar. Wenn Ihnen dies passiert, ist das Formular also beispielsweise hinter einem anderen Formular versteckt oder Sie haben es unsichtbar geschaltet.

Das geschieht gern, wenn Sie das Formular als modalen Dialog öffnen, um den aufrufenden Code anzuhalten, bis das Formular den Fokus verliert, um dann Elemente des Formulars auszulesen. Sie belegen dann etwa die OK-Schaltfläche des Formulars mit folgendem Code:

Me.Visible = False

Wenn Sie dann im aufrufenden Code vergessen, das Formular mit einer Anweisung wie der folgenden endgültig zu schließen, bleibt es im unsichtbaren Zustand geöffnet:

DoCmd.Close acForm, "frmTest"

Das Öffnungsargument ist allerdings nicht der einzige Parameter, der an bereits geöffnete Formulare nicht übergeben wird – auch die anderen Parameter wie WhereCondition, WindowMode, DataMode oder Filter funktionieren nicht.

Wenn Sie dieses Problem verhindern möchten, schließen Sie einfach immer alle geöffneten Formulare ordnungsgemäß – vor allem die unsichtbar geschalteten. Das Wichtigste ist jedoch, dass Sie das hier beschriebene Verhalten richtig einschätzen, was spätestens nach der Lektüre dieses Tipps kein Problem mehr sein sollte.

Kompletten Datensatz im Datenblatt markieren

Manchmal möchte man ein Datenblatt nicht zur Dateneingabe, sondern einfach nur zum Anzeigen und gegebenenfalls zum Auswählen von Daten verwenden. Damit der Benutzer keine Daten darin ändern kann, stellen Sie einfach die Eigenschaft Recordsettyp auf Snapshot ein – schon ist das Anfügen, ändern und Löschen der Daten nicht mehr möglich.

Das ist aber auch nur die technisch notwendige Seite der Medaille. Damit der Benutzer sich nicht verschaukelt fühlt, weil er zwar die Einfügemarke in die Felder setzen, aber keine Inhalte ändern kann, unterbinden Sie auch das.

Sie könnten dazu einfach die Eigenschaften Aktiviert und Gesperrt des Steuerelements auf Nein und Ja einstellen. Damit kann der Benutzer nicht mehr den Fokus auf die Steuerelemente setzen, aber leider kann er so auch den kompletten Datensatz nicht mehr einfach per Mausklick markieren.

Aktiviert und Gesperrt sind also die falschen Eigenschaften. Wir markieren den Datensatz einfach so, wie es auch durch einen Mausklick auf den Datensatzmarkierter am linken Rand geschehen würde – und dazu verwenden Sie die folgende Anweisung:

Application.RunCommand acCmdSelectRecord

Aber wann Der Datensatz soll schließlich bei einem Mausklick irgendwo in der Zeile markiert werden, was normalerweise das Anlegen entsprechender Beim Klicken-Ereignisprozeduren für alle angezeigten Steuerelemente beziehungsweise Felder erforderlich machen würde.

Das macht bei Formularen mit vielen Feldern aber keinen Spaß und deshalb lösen wir diese Anweisung einfach beim Ereignis Beim Anzeigen aus, das bei jedem Wechseln des Datensatzes angestoßen wird.

Wählen Sie dazu im Eigenschaftsfenster das Element Formular aus, tragen Sie für die Eigenschaft Beim Anzeigen den Wert [Ereignisprozedur] ein und klicken Sie auf die nun erscheinende Schaltfläche neben der Eigenschaft. Die dann im VBA-Editor angelegte Routine ergänzen Sie wie folgt:

Private Sub Form_Current()
    Application.RunCommand acCmdSelectRecord
    End Sub

Damit markiert das Formular direkt beim Anzeigen den ersten Datensatz und erledigt dies auch beim Wechseln des Datensatzes durch einen Mausklick auf einen anderen Datensatz.

Wenn Sie dieses Formular nun als Unterformular in einem anderen Formular einsetzen, was bei der Verwendung von Formularen in der Datenblattansicht üblich ist, wird der erste Datensatz beim Öffnen des Formulars nicht mehr komplett markiert – dies funktioniert nur noch beim Wechseln des Datensatzes.

Die Ereignisprozedur Form_Current des Unterformulars wird zwar beim Öffnen ausgelöst, aber offensichtlich sorgt der zwischenzeitliche Wechsel zum Hauptformular dafür, dass dieses den Fokus verliert und auch der erste Datensatz nicht mehr markiert ist.

Uns ist nur eine Möglichkeit bekannt, auch beim Öffnen des Formulars direkt den ersten Datensatz des Unterformulars komplett zu markieren – und zwar durch das Setzen des Timers des Hauptformulars auf ein kurzes Zeitintervall wie 1 und Hinzufügen der folgenden Routine, die durch die Ereigniseigenschaft Bei Zeitgeber ausgelöst wird:

Private Sub Form_Timer()
    Me!sfm.SetFocus
    Me!sfm.Form.Vorname.SetFocus
    Application.RunCommand acCmdSelectRecord
    Me.TimerInterval = 0
    End Sub

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Berichte und Reporting

Wie seinen Rechner, sein Auto oder das Design seiner Internetseite wird man gelegentlich auch mal das Aussehen seines Briefkopfes leid und tauscht diesen kurzerhand aus. Kurzerhand Nicht wirklich: Wenn Sie etwa mehrere Access-Anwendungen anpassen müssen, die wiederum mehrere Berichte mit Ihrem Briefkopf enthalten, wartet eine Menge Handarbeit auf Sie.

Dabei geht es doch viel leichter: Erstellen Sie doch einfach einen Unterbericht mit dem Briefkopf und fügen Sie diesen in alle anderen Berichte, die einen Briefkopf benötigen, ein. Damit brauchen Sie änderungen nur noch an einer Stelle vorzunehmen. Selbst wenn Sie mehrere Anwendungen haben, die Berichte mit einem Briefkopf enthalten, ist die Aufgabe schnell erledigt, denn Sie müssen ja nur den angepassten Bericht mit dem Briefkopf in alle relevanten Access-Datenbanken kopieren.

Und so funktioniert es: Legen Sie einen Bericht an und platzieren Sie darin die Elemente Ihres Briefkopfes. Entfernen Sie die Berichtskopfelemente aus einem vorhandenen Bericht. Fügen Sie dann den Bericht mit dem Briefkopf in den Zielbericht ein – das geht am einfachsten, wenn Sie den Zielbericht in der Entwurfsansicht öffnen und den einzufügenden Bericht aus dem Datenbankfenster an die gewünschte Stelle des Zielberichts ziehen.

VBA und Programmiertechnik

Wer keine Arbeit hat, der macht sich welche. Zum Beispiel, indem er funktionierende Codepassagen aus einer Routine in eine andere Routine kopiert. Funktioniert per Copy and Paste und liefert auch funktionell das gewünschte Ergebnis.

Manchmal programmiert man auch unbewusst an zwei Stellen innerhalb des gleichen Moduls oder zumindest innerhalb der gleichen Anwendung Codezeilen, die entweder völlig identisch sind oder zumindest genau die gleiche Funktion haben. Stehen dann einmal änderungen innerhalb dieser Code-Dubletten an, hat man direkt die doppelte (oder x-fache) Arbeit: Jede änderung müssen Sie an mehreren Stellen durchführen, damit alles wieder wie gewünscht funktioniert. Dabei lassen sich solche Probleme ganz einfach lösen: „Klammern“ Sie den doppelten Code einfach aus, indem Sie ihn in einer eigenen Routine anlegen und von den ursprünglichen Routinen darauf verweisen. Im einfachsten Fall funktioniert das nach dem folgenden Schema: Nehmen wir an, dass Sie bei bestimmten Aktionen eine Reihe von Steuerelementen in einem Formular aktivieren oder deaktivieren möchten und dass a im ganzen Modul bekannt ist:

Private Form_Load()
     If a Then
         Me!txt1.Enabled = True
         Me!txt2.Enabled = True
         Me!txt3.Enabled = True
     Else
         Me!txt1.Enabled = False
         Me!txt2.Enabled = False
         Me!txt3.Enabled = False
     End If
     ...
End Sub
Private cmdBeispiel_Click()
     If a Then
         Me!txt1.Enabled = True
         ...
End Sub

Wenn Sie dies nun bei verschiedenen Gelegenheiten tun – etwa beim öffnen des Formulars, beim Anzeigen eines neuen Datensatzes oder beim Klick auf eine bestimmte Schaltfläche – haben Sie den gleichen Code an mehreren Stellen stehen. Kommt nun noch ein weiteres Steuerelement hinzu, müssen Sie den Code an mehreren Stellen anpassen. Stattdessen erstellen Sie eine neue Funktion mit einem sinnvollen Namen, etwa SteuerelementeAnpassen.

Private Sub SteuerelementeAnpassen
     If a Then
         Me!txt1.Enabled = True
         Me!txt2.Enabled = True
         Me!txt3.Enabled = True
     Else
         Me!txt1.Enabled = False
         Me!txt2.Enabled = False
         Me!txt3.Enabled = False
     End If
End Sub

Ersetzen Sie dann diese „extrahierten“ Zeilen an allen betroffenen Stellen durch einen einfachen Aufruf der neuen Routine SteuerelementeAnpassen, etwa so:

Private Form_Load()
     SteuerelementeAnpassen
     ...
End Sub
Private cmdBeispiel_Click()
     SteuerelementeAnpassen
     ...
End Sub

Nun können Steuerelemente hinzukommen oder wegfallen, wie sie wollen, die Anpassung müssen Sie immer nur an einer Stelle vornehmen.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Christoph Spielmann, Düsseldorf

In der vorliegenden Ausgabe von Access im Unternehmen präsentieren wir Ihnen wieder einige Tipps & Tricks, die es in sich haben. Sie erfahren, wie Sie beliebige Dateien von Access aus öffnen, ohne die Anwendung auswählen zu müssen und wie Sie unerwünschte Zeichen aus Dateinamen entfernen können. Außerdem stellen wir Ihnen eine Möglichkeit vor, um ein Laufband in den Formularen Ihrer Access-Anwendung unterzubringen.

Unter Windows ist bekanntlich jede Dateierweiterung mit einer passenden Anwendung verknüpft. Dieser Tipp zeigt Ihnen, wie Sie eine Datei von Access aus direkt zusammen mit der zugeordneten Anwendung öffnen.

Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd _    As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters _    As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Quellcode 1

Public Function OpenDocument(DocumentFile As String) As Long
    Dim ret As Long
        If Len(DocumentFile) > 0 Then
            ret = ShellExecute(Application.hWndAccessApp, "open", DocumentFile, _                vbNullChar, "", 1)
            If Err Then
                OpenDocument = 0
            ElseIf ret > 32 Then
                OpenDocument = -1
            Else
                OpenDocument = ret
            End If
        Else
        OpenDocument = 0
    End If
End Function

Quellcode 2

Die Information darüber, welche Anwendungen für welche Dateien zuständig sind, ist in der Registry von Windows untergebracht. Nun wäre es sehr mühselig, die Informationen hier auszulesen. Zum Glück kann Windows da mit einer passenden API-Funktion aufwarten, die Ihnen diese Arbeit abnimmt. Diese API-Funktion trägt den Namen ShellExecute und wird wie in Quellcode 1 deklariert:

Da die einzelnen Parameter etwas unübersichtlich sind, kann der Aufruf mit Hilfe der VBA-Prozedur aus Quellcode 2 vereinfacht werden.

Public Function CreateValidFilename(ByVal Filename _    As String) As String
    Dim i As Long
    Dim Text As String
    Dim Länge As Long
    Dim Zeichen As String
    For i = 1 To Len(Filename)
        Select Case Asc(Mid$(Filename, i, 1))
            Case Is < 32, 92, 47, 58, 42, 63, 34, 60, _                62, 124
                Mid$(Filename, i, 1) = "_"
        End Select
    Next
    CreateValidFilename = Filename
End Function

Quellcode 3

Diese Funktion erwartet als Parameter lediglich den Dateinamen der zu öffnenden Datei. Als Ergebnis erhalten Sie im Fehlerfall einen Wert kleiner oder gleich 0 zurück. Wenn Sie beispielsweise die Excel-Datei C:\\Mappe1.xls in Excel öffnen möchten, dann geben Sie lediglich den folgenden Ausdruck an:

OpenDocument "C:\\Mappe1.xls"

Die komplette Funktion finden Sie im Modul modOpenDocument der BeispieldatenbankTippsTricks0206.mdb.

Bei der Eingabe eines Dateinamens sind fast alle Zeichen erlaubt. Eine Ausnahme bilden jedoch die folgenden Zeichen:

\\ / : * " < > |

Die Prozedur aus Quellcode 3 prüft einen Dateinamen auf eines dieser Zeichen und ersetzt dieses automatisch durch einen Unterstrich. Wenn Sie dieser Funktion beispielsweise den Text Umsatz 2002/2003.xls übergeben, wird dieser in Umsatz 2002_2003.xls umgewandelt und kann als Dateiname verwendet werden.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Autor: Christoph Spielmann, Düsseldorf

Auf den folgenden Seiten versorgt Sie unser Autor Christoph Spielmann mit einigen Tipps und Tricks rund um VBA, die Sie sofort in Betrieb nehmen können. Hier finden Sie beispielsweise eine Möglichkeit, die Bildschirmauflösung zu ermitteln. Das kann u. a. für die Auslegung der Größe von For-mularen sehr interessant sein. Sie lernen, wie Sie Dateien entgültig löschen (ohne doppelten Boden, direkt in den Reißwolf) und wie Sie dem Anwender von Ihrer Applikation aus eine Möglichkeit zur Verfügung stellen, mal eben eine Diskette zu formatieren. Falls Sie einmal ein bestimmtes Systemverzeichnis auf Ihrer Festplatte vermissen – keine Sorge, hier finden Sie die richtige Funktion, um es wiederzufinden. Die nachfolgend beschriebenen Funktionen packen Sie am besten gut an eine sichere Stelle – Sie werden sie immer wieder benötigen.

Einige Office-Anwendungen stellen Ihnen die aktuelle Bildschirmgröße direkt zur Verfügung. So finden Sie beispielsweise in den Eigenschaften HorizontalResolution und VerticalResolution des System-Objekts der Word-Bibliothek die Breite und die Höhe des Bildschirms in Pixel:

Breite = System.HorizontalResolution
Höhe = System.VerticalResolution
Private Declare Function GetDC Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
    (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
    (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Const HORZRES = 8
Private Const VERTRES = 10
Public Property Get ScreenHeightPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightPixels = GetDeviceCaps(nDC, VERTRES)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthPixels = GetDeviceCaps(nDC, HORZRES)
    ReleaseDC 0, nDC
End Property

Doch in der Access-Bibliothek fehlt diese Möglichkeit. Und in keiner der Bibliotheken der Office-Anwendungen finden Sie eine direkte oder indirekte Möglichkeit, die aktuelle Bildschirmauflösung in Erfahrung zu bringen (die Bildschirmauflösung hängt davon ab, ob der Anwender in den Bildschirmeinstellungen große oder kleine Bildschirmschriften oder eine beliebige Schriftgröße eingestellt hat).

Die gesuchten Werte liefert dagegen immer aktuell die API-Funktion GetDeviceCaps. Sie wird für den Gerätekontext (DC) eines bestimmten Geräts aufgerufen, etwa eines Druckers oder eben des Bildschirms.

Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Public Property Get dpiX() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiX = GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get dpiY() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiY = GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelX() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelX = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelY() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelY = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenHeightTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightTWIPS = GetDeviceCaps(nDC, VERTRES) * _
     (1440 / GetDeviceCaps(nDC, LOGPIXELSY))
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthTWIPS = GetDeviceCaps(nDC, HORZRES) * _
        (1440 / GetDeviceCaps(nDC, LOGPIXELSX))
    ReleaseDC 0, nDC
End Property

Den Gerätekontext des Bildschirms erhalten Sie über die API-Funktion GetDC, der Sie als Fenster-Handle für den ganzen Bildschirm den Wert 0 übergeben.

Nach der Verwendung des Gerätekontextes müssen Sie daran denken, ihn wieder mit der API-Funktion ReleaseDC freizugeben.

Neben dem Gerätekontext übergeben Sie der Funktion GetDeviceCaps den jeweiligen Index, zu dem Sie den gewünschten Wert erhalten wollen. über die beiden Hilfs-funktionen ScreenHeightPixels und ScreenWidthPixels erhalten Sie auf diese Weise z. B. die Bildschirmhöhe und die Bildschirmbreite.

In Quellcode 1 finden Sie zunächst die erforderlichen Deklarationen der benötigten API-Funktionen sowie der dazugehörenden Konstanten.

Die fehlende Information über die Bildschirmauflösung erhalten Sie über die Funktion GetDeviceCaps (Beispiele s. Quellcode 2). Sie liefert Ihnen direkt die vertikale und die horizontale Bildschirmauflösung in dpi (Dots per Inch).

Scheinbar sind die vertikale und die horizontale Auflösung immer gleich. Doch sollten Sie sich nicht darauf verlassen – es kann durchaus das eine oder andere Bildschirmgerät mit unterschiedlicher horizontaler und vertikaler Auflösung geben.

Aus der Bildschirmauflösung in dpi können Sie zusätzlich noch den vertikalen und den horizontalen Umrechnungsfaktor für die Maßeinheit TWIPS ermitteln.

Private Type SHFILEOPSTRUCT
    hWnd As Long
    wFunc As Long
    pFrom As String
    pTo As String
    fFlags As Integer
    fAnyOperationsAborted As Long
    hNameMappings As Long
    lpszProgressTitle As String
End Type
Quellcode 5
Private Declare Function SHFileOperation Lib _
    "Shell32.dll" Alias "SHFileOperationA" (lpFileOp _
    As SHFILEOPSTRUCT) As Long
Quellcode 6
Public Function Kill(Files As Variant, Optional ByVal _    AllowUndo As Boolean, Optional ByVal ShowProgress _    As Boolean, Optional ByVal Confirmation As _    Boolean,  Optional ByVal Simple As Boolean, _
    Optional ByVal SysErrors As Boolean, Optional _    ByVal hWnd As Long, Optional UserAborts As Variant _
    ) As Boolean
    Dim l As Long
    Dim nFileOperations As SHFILEOPSTRUCT
    Const FO_DELETE = &H3
    Const FOF_ALLOWUNDO = &H40
    Const FOF_SILENT = &H4
    Const FOF_NOCONFIRMATION = &H10
    Const FOF_SIMPLEPROGRESS = &H100
    Const FOF_NOERRORUI = &H400

Diese ist ein bei vielen externen Steuerelementen (wie etwa den Microsoft Common Controls) verwendeter Standard für bildschirmbezogene Abmessungen. Diese Maßeinheit errechnet sich als 1440stel der horizontalen bzw. vertikalen Bildschirmauflösung, wie sie von GetDeviceCaps geliefert wird (s. Quellcode 3).

Die Bildschirmgröße in TWIPS erhalten Sie dementsprechend über die Funktionen ScreenWidthTWIPS und ScreenHeightTWIPS (s. Quellcode 4)

Eine Datei zu löschen ist in VBA ein Kinderspiel – zum Beispiel mit folgender Anweisung:

Kill "c:\\autoexec.bat"

– und schon ist die Datei weg. Und zwar unrettbar verloren.

Vor allem bei vom Anwender ausgelösten Dateilöschungen sollten Sie ihm die Windows-übliche Möglichkeit einräumen, gelöschte Dateien und Ordner aus dem Papierkorb wieder herstellen zu können.

Verwenden Sie in solchen Fällen die API-Funktion SHFileOperation (s. Quellcode 6). Bei dieser können Sie wählen, ob die Datei(en) im Papierkorb landen, oder ob sie wie bei der VBA-Kill-Anweisung gleich vollständig gelöscht werden.

Außerdem können Sie die ge-wohnte Fortschrittsanzeige bieten und einige zusätzliche Einstellungen festlegen (SHFILEOPSTRUCT, Aussehen der Definition s. Quellcode 5).

Ebenso können Sie mit ihr komplette Ordner auf einen Schlag löschen – ein komplizierter, rekursiver Mechanismus mit den VBA-Anweisungen Kill und RmDir entfällt, da mit diesem Mechanismus alle untergeordneten Ordner geleert und einzeln gelöscht werden müssten.

    With nFileOperations
    If IsArray(Files) Then
        For l = LBound(Files) To UBound(Files)
            .pFrom = .pFrom & Files(l) & vbNullChar
        Next ''l
        .pFrom = .pFrom & vbNullChar
    ElseIf VarType(Files) = vbObject Then
        If TypeOf Files Is Collection Then
            For l = 1 To Files.Count
                .pFrom = .pFrom & Files(l) & vbNullChar
            Next ''l
            .pFrom = .pFrom & vbNullChar
        End If
    ElseIf VarType(Files) = vbString Then
        .pFrom = Files
        If Right$(.pFrom, 1) <> vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
        If Mid$(.pFrom, Len(.pFrom) - 1, 1) <> _            vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
    End If
    If AllowUndo Then 
      .fFlags = FOF_ALLOWUNDO
    End If
    If Not ShowProgress Then
      .fFlags = .fFlags Or FOF_SILENT
    End If
    If Not Confirmation Then
      .fFlags = .fFlags Or FOF_NOCONFIRMATION
    End If
    If Simple Then
      .fFlags = .fFlags Or FOF_SIMPLEPROGRESS
    End If
    If Not SysErrors Then
      .fFlags = .fFlags Or FOF_NOERRORUI
    End If
    .wFunc = FO_DELETE
    .hWnd = hWnd
    Kill = Not CBool(SHFileOperation(nFileOperations))
    If Not IsMissing(UserAborts) Then
      UserAborts = CBool(.fAnyOperationsAborted)
    End If
    End With
End Function

Die hier vorgestellte Ersatzfunktion Kill (s. Quellcode 7) verhält sich wie das VBA-Original, wenn Sie ihr wie gewohnt lediglich den gewünschten Dateinamen übergeben.

Sie können dieser Ersatzfunktion aber auch ein dimensioniertes oder aktuell mit der Array-Funktion zusammengestelltes Array oder eine Collection aus einzelnen Datei- und Ordnerpfaden übergeben. Und Sie können Wildcards (etwa „*.*“ oder „*.bas“) verwenden.

Die gewünschte Funktionalität legen Sie in den einzelnen optionalen Parametern fest. Sollen die Dateien in den Papierkorb verschoben werden, setzen Sie AllowUndo gleich True. Soll der Windows-übliche Fortschrittsdialog mit der Möglichkeit zum Abbrechen des Vorgangs angezeigt werden, setzen Sie ShowProgress gleich True.

Die Rückfrage, ob wirklich gelöscht werden soll, legen Sie mit Confirmation gleich True fest. Eine etwas vereinfachte Fortschrittsanzeige, bei der die Anzeige der gerade bearbeiteten Dateinamen unterbleibt, wählen Sie mit Simple gleich True. Wenn Sie im Fall eines Fehlers die Windows-Anzeige dieses Fehlers beibehalten wollen, setzen Sie SysErrors gleich True.

Unabhängig davon, wie Sie den letztgenannten Parameter setzen, gibt die Funktion Kill den Wert True zurück, wenn ein Fehler aufgetreten ist. Allerdings lässt sich der Fehler nicht näher spezifizieren – Sie müssen auf andere Weise prüfen, was schief gegangen sein könnte, z. B. Datei nicht vorhanden, gesperrt u. ä.

Hat der Anwender bei den gelegentlichen Rückfragen des Systems (wie etwa Löschen einer Systemdatei o. ä.) beispielsweise einzelne Dateien übersprungen, können Sie diese Information über den Parameter UserAborts erhalten, in der Sie dazu eine Variable übergeben müssen. Allerdings bleibt Ihnen auch hierbei nur übrig, selbst herausfinden, welche Dateien übersprungen worden sind.

Private Declare Function GetDesktopWindow _    Lib "user32" () As Long
Private Declare Function SHFormatDrive Lib "shell32" _    (ByVal hWnd As Long, ByVal Drive As Long, ByVal _    fmtID As Long, ByVal Options As Long) As Long
Public Enum fdReturnConstants
  fdRetSuccess = 0
  fdRetError = -1
  fdRetCancelled = -2
  fdRetNotFormattable = -3
  fdRetInvalidDrive = -4
End Enum

Das VBA-Original der Kill-Anweisung können Sie anstelle dieser erweiterten Kill-Funktion weiterhin jederzeit aufrufen. Dazu setzen Sie einfach den Herkunftsbezeichner (Qualifizierer) davor: „VBA.Kill …“.

Sie möchten es dem Anwender ermöglichen, in Ihrem Programm eine Diskette frisch zu formatieren Dann sollten Sie sich nicht lange mit der Entwicklung eigener Formatier-Routinen und Formatier-Dialoge aufhalten, sondern dem Anwender den entsprechenden Standard-Dialog anzeigen.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Autor: Christoph Spielmann, Düsseldorf

Auf den folgenden Seiten versorgt Sie unser Autor Christoph Spielmann mit einigen Tipps und Tricks rund um VBA, die Sie sofort in Betrieb nehmen können. Hier finden Sie beispielsweise eine Möglichkeit, die Bildschirmauflösung zu ermitteln, was z. B. für die Auslegung der Größe von Formularen sehr interessant sein kann. Sie lernen, wie Sie Dateien richtig löschen (ohne doppelten Boden, direkt in den Reißwolf) und wie Sie dem Anwender von Ihrer Applikation aus eine Möglichkeit zur Verfügung stellen, mal eben eine Diskette zu formatieren. Falls Sie einmal ein bestimmtes Systemverzeichnis auf Ihrer Festplatte vermissen – keine Sorge, hier finden Sie die richtige Funktion, um es wiederzufinden. Die nachfolgend beschrieben packen Sie am besten gut an eine sichere Stelle – Sie werden sie immer wieder benötigen.

Einige Office-Anwendungen stellen Ihnen die aktuelle Bildschirmgröße direkt zur Verfügung. So finden Sie beispielsweise in den Eigenschaften HorizontalResolution und VerticalResolution des System-Objekts der Word-Bibliothek die Breite und die Höhe des Bildschirms in Pixel:

Breite = System.HorizontalResolution
Höhe = System.VerticalResolution
Private Declare Function GetDC Lib "user32" _
    (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" _
    (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
    (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Const HORZRES = 8
Private Const VERTRES = 10
Public Property Get ScreenHeightPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightPixels = GetDeviceCaps(nDC, VERTRES)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthPixels() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthPixels = GetDeviceCaps(nDC, HORZRES)
    ReleaseDC 0, nDC
End Property

Doch in der Access-Bibliothek fehlt diese Möglichkeit. Und in keiner der Bibliotheken der Office-Anwendungen finden Sie eine direkte oder indirekte Möglichkeit, die aktuelle Bildschirmauflösung in Erfahrung zu bringen (die Bildschirmauflösung hängt davon ab, ob der Anwender in den Bildschirmeinstellungen große oder kleine Bildschirmschriften oder eine beliebige Schriftgröße eingestellt hat).

Die gesuchten Werte liefert dagegen immer aktuell die API-Funktion GetDeviceCaps. Sie wird für den Gerätekontext (DC) eines bestimmten Geräts aufgerufen, etwa eines Druckers oder eben des Bildschirms.

Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY = 90
Public Property Get dpiX() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiX = GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get dpiY() As Long
    Dim nDC As Long
    nDC = GetDC(0)
    dpiY = GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelX() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelX = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSX)
    ReleaseDC 0, nDC
End Property
Public Property Get TwipsPerPixelY() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    TwipsPerPixelY = 1440 / _        GetDeviceCaps(nDC, LOGPIXELSY)
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenHeightTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenHeightTWIPS = GetDeviceCaps(nDC, VERTRES) * _
     (1440 / GetDeviceCaps(nDC, LOGPIXELSY))
    ReleaseDC 0, nDC
End Property
Public Property Get ScreenWidthTWIPS() As Single
    Dim nDC As Long
    nDC = GetDC(0)
    ScreenWidthTWIPS = GetDeviceCaps(nDC, HORZRES) * _
        (1440 / GetDeviceCaps(nDC, LOGPIXELSX))
    ReleaseDC 0, nDC
End Property

Den Gerätekontext des Bildschirms erhalten Sie über die API-Funktion GetDC, der Sie als Fenster-Handle für den ganzen Bildschirm den Wert 0 übergeben.

Nach der Verwendung des Gerätekontextes müssen Sie daran denken, ihn wieder mit der API-Funktion ReleaseDC freizugeben.

Neben dem Gerätekontext übergeben Sie der Funktion GetDeviceCaps einen Index, zu dem Sie den gewünschten Wert erhalten wollen. Zum Beispiel die Bildschirmhöhe und die Bildschirmbreite liefern auf diese Weise die beiden folgenden Hilfsfunktionen ScreenHeightPixels und ScreenWidthPixels.

In Quellcode 1 finden Sie zunächst die erforderlichen Deklarationen der benötigten API-Funktionen sowie der dazugehörenden Konstanten.

Die fehlende Information über die Bildschirmauflösung erhalten Sie über die Funktion GetDeviceCaps (Beispiele s. Quellcode 2) Sie liefert Ihnen direkt die vertikale und die horizontale Bildschirmauflösung in dpi (Dots per Inch).

Scheinbar sind die vertikale und die horizontale Auflösung immer gleich. Doch sollten Sie sich nicht darauf verlassen – es mag durchaus das eine oder andere Bildschirmgerät mit unterschiedlicher horizontaler und vertikaler Auflösung geben.

Aus der Bildschirmauflösung in dpi können Sie zusätzlich noch den vertikalen und den horizontalen Umrechnungsfaktor für die Maßeinheit TWIPS ermitteln.

Private Type SHFILEOPSTRUCT
    hWnd As Long
    wFunc As Long
    pFrom As String
    pTo As String
    fFlags As Integer
    fAnyOperationsAborted As Long
    hNameMappings As Long
    lpszProgressTitle As String
End Type
Quellcode 5
Private Declare Function SHFileOperation Lib _
    "Shell32.dll" Alias "SHFileOperationA" (lpFileOp _
    As SHFILEOPSTRUCT) As Long
Quellcode 6
Public Function Kill(Files As Variant, Optional ByVal _    AllowUndo As Boolean, Optional ByVal ShowProgress _    As Boolean, Optional ByVal Confirmation As _    Boolean,  Optional ByVal Simple As Boolean, _
    Optional ByVal SysErrors As Boolean, Optional _    ByVal hWnd As Long, Optional UserAborts As Variant _
    ) As Boolean
    Dim l As Long
    Dim nFileOperations As SHFILEOPSTRUCT
    Const FO_DELETE = &H3
    Const FOF_ALLOWUNDO = &H40
    Const FOF_SILENT = &H4
    Const FOF_NOCONFIRMATION = &H10
    Const FOF_SIMPLEPROGRESS = &H100
    Const FOF_NOERRORUI = &H400

Diese ist ein bei vielen externen Steuerelementen (wie etwa den Microsoft Common Controls) verwendeter Standard für bildschirmbezogene Abmessungen. Diese Maßeinheit errechnet sich als 1440tel der horizontalen bzw. vertikalen Bildschirmauflösung, wie sie von GetDeviceCaps geliefert wird (s. Quellcode 3).

Die Bildschirmgröße in TWIPS erhalten Sie dementsprechend über die Funktionen ScreenWidthTWIPS und ScreenHeightTWIPS (s. Quellcode 4)

Eine Datei zu löschen ist in VBA ein Kinderspiel – zum Beispiel mit folgender Anweisung:

Kill "c:\\autoexec.bat"

– und schon ist die Datei weg. Und unrettbar verloren.

Vor allem bei vom Anwender ausgelösten Dateilöschungen sollten Sie ihm daher die Windows-übliche Möglichkeit einräumen, gelöschte Dateien (und Ordner) aus dem Papierkorb wieder herzustellen zu können.

Verwenden Sie in solchen Fällen die API-Funktion SHFileOperation (s. Quellcode 6). Bei dieser können Sie wählen, ob die Datei(en) im Papierkorb landen, oder ob sie wie bei der VBA-Kill-Anweisung gleich vollständig gelöscht werden.

Außerdem können Sie die gewohnte Fortschrittsanzeige bieten und einige Einstellungen mehr festlegen (SHFILEOPSTRUCT, Aussehen der Definition s. Quellcode 5).

Ebenso können Sie mit ihr komplette Ordner auf einen Schlag löschen – ein komplizierter, rekursiver Mechanismus mit den VBA-Anwiesungen Kill und RmDir entfällt, mit dem alle untergeordneten Ordner geleert und einzeln gelöscht werden müssten.

    With nFileOperations
    If IsArray(Files) Then
        For l = LBound(Files) To UBound(Files)
            .pFrom = .pFrom & Files(l) & vbNullChar
        Next ''l
        .pFrom = .pFrom & vbNullChar
    ElseIf VarType(Files) = vbObject Then
        If TypeOf Files Is Collection Then
            For l = 1 To Files.Count
                .pFrom = .pFrom & Files(l) & vbNullChar
            Next ''l
            .pFrom = .pFrom & vbNullChar
        End If
    ElseIf VarType(Files) = vbString Then
        .pFrom = Files
        If Right$(.pFrom, 1) <> vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
        If Mid$(.pFrom, Len(.pFrom) - 1, 1) <> _            vbNullChar Then
            .pFrom = .pFrom & vbNullChar
        End If
    End If
    If AllowUndo Then 
      .fFlags = FOF_ALLOWUNDO
    End If
    If Not ShowProgress Then
      .fFlags = .fFlags Or FOF_SILENT
    End If
    If Not Confirmation Then
      .fFlags = .fFlags Or FOF_NOCONFIRMATION
    End If
    If Simple Then
      .fFlags = .fFlags Or FOF_SIMPLEPROGRESS
    End If
    If Not SysErrors Then
      .fFlags = .fFlags Or FOF_NOERRORUI
    End If
    .wFunc = FO_DELETE
    .hWnd = hWnd
    Kill = Not CBool(SHFileOperation(nFileOperations))
    If Not IsMissing(UserAborts) Then
      UserAborts = CBool(.fAnyOperationsAborted)
    End If
    End With
End Function

Die hier vorgestellte Ersatzfunktion Kill (s. Quellcode 7) verhält sich wie das VBA-Original, wenn Sie ihr (wie gewohnt) lediglich den gewünschten Dateinamen übergeben.

Sie können ihr aber auch ein (dimensioniertes oder aktuell mit der Array-Funktion zusammengestelltes) Array oder eine Collection aus einzelnen Datei- und Ordnerpfaden übergeben. Und sie können Wildcards (etwa „*.*“ oder „*.bas“) verwenden.

Die gewünschte Funktionalität legen Sie in den einzelnen optionalen Parametern fest. Sollen die Dateien in den Papierkorb verschoben werden, setzen Sie AllowUndo gleich True. Soll der Windows-übliche Fortschrittsdialog mit Möglichkeit zum Abbrechen des Vorgangs angezeigt werden, setzen Sie ShowProgress gleich True.

Die Rückfrage, ob wirklich gelöscht werden soll, legen Sie mit Confirmation gleich True fest. Eine etwas vereinfachte Fortschrittsanzeige, bei der die Anzeige der gerade bearbeiteten Dateinamen unterbleibt, wählen Sie mit Simple gleich True. Wenn Sie im Falle eines Fehlers die Windows-Anzeige dieses Fehlers beibehalten wollen, setzen Sie SysErrors gleich True.

Unabhängig davon, wie Sie den letztgenannten Parameter setzen, gibt die Funktion Kill den Wert True zurück, wenn ein Fehler aufgetreten ist. Allerdings lässt sich der Fehler nicht näher spezifizieren – Sie müssen auf andere Weise prüfen, was schief gegangen sein könnte (Datei nicht vorhanden, gesperrt u. a.).

Hat der Anwender bei den gelegentlichen Rückfragen des Systems (Löschen einer Systemdatei o. ä.) beispielsweise einzelne Dateien übersprungen, können Sie diese Information über den Parameter UserAborts erhalten, in der Sie dazu eine Variable übergeben müssen. Allerdings müssen Sie auch hierbei wieder selbst herausfinden, welche Dateien übersprungen worden sind.

Private Declare Function GetDesktopWindow _    Lib "user32" () As Long
Private Declare Function SHFormatDrive Lib "shell32" _    (ByVal hWnd As Long, ByVal Drive As Long, ByVal _    fmtID As Long, ByVal Options As Long) As Long
Public Enum fdReturnConstants
  fdRetSuccess = 0
  fdRetError = -1
  fdRetCancelled = -2
  fdRetNotFormattable = -3
  fdRetInvalidDrive = -4
End Enum

Das VBA-Original der Kill-Anweisung können Sie anstelle dieser erweiterten Kill-Funktion weiterhin jederzeit aufrufen. Dazu setzen Sie einfach den Herkunftsbezeichner (Qualifizierer) davor: „VBA.Kill …“.

Sie möchten es dem Anwender ermöglichen, in Ihrem Programm eine Diskette frisch zu formatieren Dann sollten Sie sich nicht lange mit der Entwicklung eigener Formatier-Routinen und -Dialogen aufhalten, sondern dem Anwender den entsprechenden Standard-Dialog anzeigen.

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

André Minhorst, Duisburg

Die Anzeige von Berichten bringt in der Regel zwei Probleme mit sich:

Erstens ist der Bericht selten so an das Berichtsfenster angepasst, dass der Betrachter den gewünschten Ausschnitt in einer geeigneten Auflösung vorfindet (s. Abb. 1).

Und zweitens entsprechen die Proportionen des Berichtsfensters beim öffnen selten denen des Berichtes.

Wenn der Benutzer einer Datenbankanwendung nur hin und wieder einen Bericht in der Vorschau öffnet, mögen die Probleme sicher nicht gravierend sein. Bei einer häufigen Anwendung der Berichtsvorschau wird das Anpassen der Größe des Fensters und der Auflösung jedoch schnell zu einer nervraubenden Tätigkeit.

Abb. 1: Ein willkürlich geöffneter Access-Bericht…

Mit einer kleinen Schaltfläche und zwei einfachen Befehlen können Sie dem Benutzer Ihrer Datenbankanwendung das Leben sehr erleichtern. Das öffnen des Berichtes in der gewünschten Größe mit den richtigen Proportionen ist dann kein Problem mehr (s. Abb. 2).

Abb. 2: … und einer, der auf die Fenstergröße zugeschnitten ist.

Anpassen der Größe des Berichtsfensters

Die Größe eines Berichtsfensters lässt sich nach dem öffnen des Berichtes mit der Methode MoveSize des DoCmd-Befehls einstellen. Die Methode hat vier Parameter: Die horizontale und vertikale Position des oberen, linken Eckpunktes und die Höhe und die Breite des aktiven Fensters.

Der Befehl hat beispielsweise folgendes Aussehen:

DoCmd.MoveSize 10,10,1000,1000

Der Befehl wirkt sich immer auf das aktive Fenster aus.

Private Sub btnBerichtPassendAnzeigen_Click()
    DoCmd.OpenReport "Alphabetische Artikelliste", _        acPreview
    DoCmd.RunCommand acCmdFitToWindow
    DoCmd.MoveSize 20, 20, 8000, 12000

Anpassen der Auflösung des Berichtes

Die Auflösung eines Berichts können Sie ebenfalls mit einer Methode des DoCmd-Befehls verändern: Diesmal handelt es sich um die Methode RunCommand, mit der Sie alle Anweisungen ausführen können, die Sie auch in den Menüleisten von Access vorfinden.

Dabei gibt es für jeden Menübefehl eine bestimmte Konstante. Im vorliegenden Fall sind alle Konstanten interessant, mit denen man die Auflösung eines Berichtes beeinflussen kann.

Auflösung

Konstante

10%

acCmdZoom10

25%

acCmdZoom25

50%, 75%, 100%, 150%, 200%

wie oben, nur mit entsprechenden Zahlen

Passend zum Fenster

acFitToWindow

Tab. 1: Berichtsauflösungen und die entsprechenden Konstanten

In Tab. 1 finden Sie die Auflösungen in Prozent sowie die entsprechende zu verwendende Konstante.

Anwenden derBerichtseinstellungen

Eine professionelle Access-Datenbankanwendung verfügt normalerweise über geeignete Schaltflächen zur Anzeige von Daten in Berichten.

Im Folgenden verwenden Sie ein kleines Formular mit einer solchen Schaltfläche, um den Bericht in der richtigen Größe und Auflösung anzuzeigen.

Nachdem Sie eine Schaltfläche namens btnBerichtsvorschau in ein beliebiges Formular eingefügt haben, hinterlegen Sie die Prozedur aus Quellcode 1 für die Ereigniseigenschaft Beim Klicken der Schaltfläche.

Der Bericht wird nun in einem Berichtsfenster angezeigt, das ungefähr proportional zu dem im DIN-A4-Format vorliegenden Bericht ist.

Eine interessante Neuerung von Office 2000 ist die Anzeige von eigenen Einträgen in der Taskleiste für jedes geöffnete Objekt einer Anwendung. Bezogen auf Access bedeutet dies, dass Sie beispielsweise einzelne Formulare oder Berichte über einen Mausklick auf den entsprechenden Eintrag in die Taskleiste aktivieren können (s. Abb. 3).

Manch einer mag diese Eigenschaft aber auch lästig finden. Daher ist es ganz günstig, dass Microsoft eine Option zum Deaktivieren der Taskleisteneinträge vorgesehen hat:

öffnen Sie einfach den Dialog Optionen über den Menübefehl Extras/Optionen. Im Register Ansicht finden Sie unter Anzeigen die Option Fenster in Taskleiste. Entfernen Sie einfach den Haken aus dem Kontrollkästchen und Sie haben wieder mehr Platz in der Taskleiste (s. Abb. 4).

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar

Tipps und Tricks

Autor: André Minhorst, Duisburg

Die im folgenden beschriebenen Tipps und Tricks stammen von unserem Autor André Minhorst. Herr Minhorst ist ein richtiger Access-Praktiker. Er arbeitet täglich mit diesem Programm und kennt somit alle seine Stärken und Schwächen. Wir, die Access-Redaktion, haben ihn gebeten, doch ein paar Kniffe aus seinem Arbeitsalltag aufzuschreiben. Einige davon erweisen sich erst beim praktischen Einsatz als wirklich hilfreich. Danach will man sie allerdings nicht mehr missen!

Auf die Elemente des Desktop kann man bequem über das Kontextmenü zugreifen (Klick mit der rechten Maustaste auf ein Objekt). Das Kontextmenü bietet verschiedene Befehle, die auf das entsprechende Programm angewendet werden können. Dies gilt auch für Access-Datenbanken. Leider bietet das Kontextmenü längst nicht alle Befehle, die man sich wünscht – so fehlen beispielsweise Befehle zum Komprimieren oder Reparieren einer Accessdatenbank. Im vorliegenden Beitrag erfahren Sie, wie Sie das Kontext-menü um die gewünschten Befehle erweitern können.

Hinweis

Bitte beachten Sie die Hinweise bezüglich der Unterschiede zwischen Access 97 und 2000.

Das Kontextmenü einer Access-Datenbank

Um eine Datenbank vom Desktop aus starten zu können, müssen Sie zunächst eine Verknüpfung zur Datenbank auf dem Desktop erstellen. Anschließend können Sie das Kontextmenü der Datenbank anzeigen, indem Sie mit der rechten Maustaste auf das entsprechende Symbol klicken (Abb. 1).

Im Kontextmenü finden Sie Befehle zum öffnen der Datenbank sowie zum Bearbeiten der Verknüpfung. Außerdem finden Sie einige weitere Befehle wie z. B. Norman Virus Control… Solche Befehle finden Sie allerdings nur, wenn die entsprechenden Anwendungen auf Ihrem Rechner installiert sind und die Anwendungen sich automatisch in das Kontextmenü einblenden.

Abb. 1: Kontextmenü einer Datenbank vor der Bearbeitung.

Hinzufügen von weiteren Befehlen

Leider fehlen solche Befehle wie z. B. Komprimieren oder Reparieren. Wären solche Befehle vorhanden, könnte man die entsprechenden Aktionen ausführen, ohne die Datenbank zunächst mit Access öffnen zu müssen.

Wie viele andere Eigenschaften befinden sich auch die Informationen über die Einträge des Kontextmenüs in der Windows-Registratur. Um dem Kontextmenü also einen weiteren Befehl hinzuzufügen, müssen Sie zunächst einmal die Registratur von Windows öffnen:

  • Wählen Sie aus dem Startmenü den Eintrag Ausführen… aus.
  • Geben Sie im Feld öffnen des Dialogs Ausführen den Befehl Regedit ein (Abb. 2).
  • Abb. 2: Starten der Windows-Registratur

    Daraufhin öffnet sich der Editor, mit dem Sie die Registratur (Registrierdatenbank) bearbeiten können (Abb. 3).

    In der Verzeichnisstruktur müssen Sie sich zunächst einmal zu dem gewünschten Eintrag durchschlagen. Der Eintrag lautet:

    [HKEY_CLASSES_ROOT]\\Access.Application.8

    \\shell

    Je nachdem, ob Sie mit Access 97 oder mit Access 2000 arbeiten, geben Sie statt der Versionsnummer 8 (Access 97) die 9 (Access 2000) ein.

    Abb. 3: Der Registrierungs-Editor

    Sie müssen nun unter dem Schlüssel Shell einen weiteren Schlüssel anlegen. Gehen Sie dazu folgendermaßen vor:

  • Klicken Sie mit der rechten Maustaste auf den Schlüssel Shell, um das Kontextmenü anzuzeigen.
  • Wählen Sie im Kontextmenü den Eintrag Neu ( Schlüssel aus.
  • ändern Sie den Namen des neu erscheinenden Schlüssels in Komprimieren um.
  • Klicken Sie nun mit der rechten Maustaste auf den neuen Eintrag, um sein Kontextmenü anzuzeigen.
  • Wählen Sie im Kontextmenü erneut den Eintrag Neu ( Schlüssel aus und nennen Sie den Schlüssel command.
  • Nachdem Sie nun die entsprechenden Schlüssel erstellt haben, müssen Sie dem Schlüssel command noch einen Wert zuweisen.

    Klicken Sie dazu im rechten Bereich des Registrierungs-Editors doppelt auf den Eintrag (Standard). Es öffnet sich ein weiteres Fenster, in welches Sie den Wert des Schlüssels eingeben können (Abb. 4).

    Abb. 4: Eingeben eines neuen Schlüsselwertes

    Den unter dem Schlüssel command angegebenen Befehl führt Access für die angegebene Da-tenbank mit der Option /compact aus. Beachten Sie, dass Sie den Pfad zu der Access-Anwendung an Ihren eigenen Rechner anpassen müssen. Allgemein lautet die Syntax der Anweisung:

    „<Pfad zu MSAccess.exe>“ /compact „%1“

    Abb. 5: Das Kontextmenü mit dem neuen Eintrag

    Wenn Sie nun das Kontextmenü einer Datenbankverknüpfung auf dem Desktop anzeigen, finden Sie hier den neuen Eintrag Komprimieren (Abb. 5). Wenn Sie den Befehl aufrufen, wird Access automatisch geöffnet, die Komprimierung durchgeführt und Access wieder von selbst geschlossen.

    Anlegen weiterer Einträge

    Diese Methode ist für alle Startoptionen von Access anwendbar. Beispielsweise können Sie einen weiteren Eintrag für das Reparieren einer Datenbank anlegen oder einen, mit dem Sie die Datenbank gleichzeitig reparieren und komprimieren können.

    Sie müssen lediglich einen neuen Schlüssel mit dem im Kontextmenü anzuzeigenden Eintrag anlegen und beim Schlüsselwert die gewünschte Startoption festlegen – also z. B. Reparieren als Schlüssel und „<Pfad zu MSAccess.exe>“ /compact „%1“ als Schlüsselwert des Unterschlüssels command.

    Wenn Sie eine Datenbank reparieren, komprimieren oder in eine MDE-Datenbank umwandeln möchten, sollten Sie vorher eine Sicherheitskopie der Datenbank anlegen. Normalerweise erledigen Sie dies im Windows-Explorer. Wenn Sie aber Access einmal gestartet und den Dialog zur Auswahl der gewünschten Datenbank vor sich haben, können Sie das Anlegen der Sicherheitskopie auch direkt vor Ort vornehmen.

    Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
    Hier geht es zur Bestellung des Jahresabonnements des Magazins Access im Unternehmen:
    Zur Bestellung ...
    Danach greifen Sie sofort auf alle rund 1.000 Artikel unseres Angebots zu - auch auf diesen hier!
    Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

    Schreibe einen Kommentar