Wenn sich mal wieder ein Access-Einsteiger in einem Forum oder einer Newsgroup nach Möglichkeiten erkundigt, das Aussehen des mit der MsgBox-Funktion angezeigten Meldungsfensters anzupassen, gibt es nur ein müdes Lächeln und den Hinweis, dass man sich da wohl schon auf die Hinterbeine setzen und ein eigenes Meldungsfenster bauen müsse – natürlich als Formular. Diese Arbeit nehmen wir Ihnen nun ab – mit dem Access-im-Unternehmen-Meldungsfenster.
Meldungsfenster braucht man wirklich oft, und entgegen dem Namen dient es ja nicht nur zur Anzeige von Meldungen, sondern auch zum Realisieren einfacher Dialoge. So stellen Meldungsfenster nicht nur die OK-Schaltfläche zum Schließen der Meldung bereit, sondern auch noch einige andere Kombinationen wie OK und Abbrechen oder Ja und Nein. Und da MsgBox nicht nur eine Methode, sondern – wie einleitend erwähnt – eine Funktion ist, liefert es auch einen Rückgabewert, der einer Konstanten für die vom Benutzer ausgewählten Schaltflächen entspricht und ganz einfach ausgewertet werden kann.
Nun haben Entwickler und Anwender manchmal sehr spezielle Anforderungen und Wünsche, die sich hier und da auch auf die Gestaltung des Meldungsfensters beziehen. In der Tat liefert dieses nur mäßige Möglichkeiten der Anpassung und diese beschränken sich auf die Auswahl des angezeigten Symbols, des Meldungstextes, des Fenstertitels und der zur Verfügung stehenden Schaltflächen. Selbst die Breite des Meldungsfensters kann nur über die breiteste Textzeile beeinflusst werden.
Wer also etwa auf sehbehinderte Benutzer Rücksicht nehmen und mit einer entsprechenden Schriftgröße aufwarten möchte, kommt mit dem herkömmlichen Meldungsfenster nicht weit – außer, er stellt die Schriftgröße direkt systemweit um (Systemsteuerung|Anzeige|Darstellung|Schriftgrad).
Also legen Sie selbst Hand an und bauen Ihr eigenes Meldungsfenster.
Gleicher Aufruf, anderes Meldungsfenster
Der Clou bei der MsgBox-Funktion ist der folgende: Sie können eine eigene öffentliche Funktion namens MsgBox programmieren und damit die eingebaute MsgBox-Funktion überschreiben. Probieren Sie es einfach einmal mit der folgenden einfachen Funktion aus:
Public Function MsgBox()
Debug.Print "MsgBox überschrieben"
End Function
Wenn Sie nun im Direktfenster den Befehl MsgBox absetzen, erscheint dort lediglich der erwartete Text:
MsgBox
MsgBox überschrieben
Natürlich fehlt zum MsgBox-Ersatz noch einiges mehr, aber Sie können das Meldungsfenster, das Sie auf den folgenden Seiten kennen lernen, zumindest auch nachträglich in bestehende Anwendungen einbauen und davon profitieren.
Funktionen des selbst gebauten
Meldungsfensters
Was soll Ihr eigenes Meldungsfenster nun bieten, was das vorherige nicht konnte Es gibt da eine Menge Möglichkeiten:
- Auswahl eigener Hintergrund- und Textfarben
- Auswahl neuer Symbole
- Andere Schriftart und -größe
- Gemischte Formatierung
Die Hintergrund- und Textfarben können Sie entweder, wie nachfolgend als einfachere Variante vorgestellt, direkt in das als Meldungsfenster missbrauchte Formular einstellen. Es gibt natürlich auch die Möglichkeit, solche und andere Informationen in einer Optionen-Tabelle oder an anderer Stelle zu speichern und vom Benutzer über einen Optionen-Dialog einstellen zu lassen. Letzteres würde jedoch den Rahmen hier sprengen, sodass wir es bei dem Einstellen einer anwendungsweiten Farbe für Schrift und Hintergrund belassen.
Statt der üblicherweise verwendeten Symbole wie jene aus Bild 1 können Sie also durchaus eigene Symbole einsetzen. Im vorliegenden Falle nehmen wir allerdings mit den üblichen Symbolen vorlieb.
Bild 1: Die Symbole des Meldungsfensters
Mit Schriftart und -größe verhält es sich wie mit den Farben: Sie können diese vom Benutzer einstellen lassen oder aber eigene Einstellungen vorgeben – auch hier verwenden wir aus Gründen der übersicht die einfachere Variante.
Fehlt noch die gemischte Formatierung: Es ist klar, dass man für völlig flexible Formatierungen ein RTF-Steuerelement oder das in Access 2007 neu eingeführte Richtext-Feld verwenden müsste. Dies ist aber nicht das Ziel: Ein Meldungsfenster soll den Benutzer kurz über einen Sachverhalt informieren beziehungsweise eine Entscheidung über die weitere Vorgehensweise einholen und keine Sammlung bunter und verschieden formatierter Buchstaben sein.
Was völlig in Ordnung ist und bis Access 97 auch möglich war, ist der Einsatz einer fett gedruckten ersten Zeile als überschrift. In Access 97 wurde diese erste Zeile von den folgenden durch das Klammeraffe-Zeichen (@) getrennt, auch weitere Zeilenumbrüche mit nachfolgender Leerzeile konnten hiermit eingefügt werden. Diese Möglichkeiten soll auch unser Meldungsfenster nachbilden.
Aussehen des Meldungsfensters
Als Meldungsfenster verwenden Sie ein einfaches Formular. Dieses versorgen Sie mit folgenden Steuerelementen:
- picCritical, picExclamation, picInformation, picQuestion: Bildsteuerelemente, die Eigenschaften Links und Oben erhalten den Wert 0,2cm.
- lblHeader: Bezeichnungsfeld für die überschrift, Schriftbreite: Fett
- lblText: Bezeichnungsfeld für den eigentlichen Text
- cmd1, cmd2, cmd3: Schaltflächen, die nach Bedarf eingeblendet und mit verschiedenen Texten beschriftet werden. Das Formular selbst soll frmMsgBox heißen. Stellen Sie dort die Eigenschaften Bildlaufleisten, Datensatzmarkierer, Navigationsschaltflächen und Trennlinien auf Nein ein. Die Schaltflächen platzieren Sie im Fußbereich des Formulars.
Die Größe und Position der Bezeichnungsfelder und der Schaltflächen ist zunächst unerheblich, diese Eigenschaften werden später per Code an den enthaltenen Text angepasst. Stellen Sie jedoch die Sichtbarkeit der Schaltflächen mit der Eigenschaft Visible auf False ein. Außerdem sollten Sie die Eigenschaft Textausrichtung der beiden Bezeichnungsfelder auf Zentriert setzen.
Bilder hinzufügen
Für die Symbole fügen Sie einfach vier Bildsteuerelemente hinzu und füllen diese mit Bilddateien in entsprechender Hintergrundfarbe – in der Beispieldatenbank sind diese weiß.
Die Schaltflächen
Das selbst gebaute Meldungsfenster soll die gleichen Schaltflächen-Kombinationen bieten wie das Original-Meldungsfenster. Bild 2 zeigt im überblick, welche Konstante welche Schaltflächenkombination erzeugt. Zählt man einmal durch, kommt man auf sechs verschiedene Schaltflächen: Abbrechen, Ignorieren, Ja, Nein, OK und Wiederholen.
Maximal zeigt ein Meldungsfenster jedoch nur drei Schaltflächen gleichzeitig an – vier, wenn man die mögliche Hilfe-Schaltfläche mitzählt (diese lassen wir jedoch weg – einen Meldungstext sollte man schon so formulieren, dass der Benutzer die für ihn richtige Schaltfläche intuitiv auswählt). Wie viele Schaltflächen legen wir also an Es gibt zwei naheliegende Varianten:
- Sie legen für jeden Befehl eine eigene Schaltfläche an und blenden jeweils die nicht benötigten Schaltflächen aus. Der Vorteil ist, dass man die Antwort des Benutzers direkt anhand der angeklickten Schaltfläche ermitteln kann.
- Sie legen nur so viele Schaltflächen an, wie gleichzeitig angezeigt werden sollen. Lässt man die Hilfe-Schaltfläche weg, wären dies drei. Da die Bezeichnungen der Schaltflächen generisch wären, müsste man die Bedeutung der jeweiligen Schaltfläche entweder aus der dynamisch zugewiesenen Beschriftung entnehmen oder man schreibt die Antwortkonstante irgendwo anders hin – beispielsweise in die Tag-Eigenschaft der Schaltfläche.
Die hier zum Einsatz kommende Variante haben wir schon vorweggenommen – wir setzen auf die Minimalanzahl an Schaltflächen, nämlich drei.
Aufruf des Meldungsfensters
Um das Formular als alternatives Meldungsfenster aufzurufen, brauchen Sie eine öffentliche Funktion namens MsgBox, die genau die gleichen Parameter wie die eigentliche Funktion liefert.
Dass Sie nicht alle Parameter auswerten (HelpFile und Context bleiben außen vor), spielt keine Rolle; aus Kompatibilitätsgründen müssen diese Parameter aber zumindest in der Parameterliste der Funktion enthalten sein, damit bereits in einer Anwendung vorhandene Aufrufe keine Fehler auslösen.
Die folgende Funktion prüft zunächst, ob der Parameter Title angegeben wurde, und legt gegebenenfalls einen eigenen Fenstertitel fest. Danach steht dem öffnen des Formulars als modaler Dialog nichts mehr im Wege. Einzige Aufgabe dieses Aufrufs ist es, die Parameter mit dem OpenArgs-Argument zu übergeben, was in Form einer durch das Pipe-Zeichen (|) getrennten Zeichenkette geschieht. Diese enthält den Zahlenwert für die Konstanten (Schaltflächen, Symbol, Standardschaltfläche), die Meldung sowie den Fenstertitel.
Function MsgBox(Prompt, Optional Buttons _
As VbMsgBoxStyle = vbOKOnly, _
Optional Title, _
Optional HelpFile, _
Optional Context) As VbMsgBoxResult
On Error Resume Next
If IsMissing(Title) Then Title = _
"Access im Unternehmen-Meldungsfenster"
DoCmd.OpenForm "frmMsgbox", , , , , _
acDialog, CStr(Buttons) & "|" _
& CStr(Prompt) & "|" & CStr(Title)
MsgBox = Forms!frmMsgbox.RetVal
DoCmd.Close acForm, "frmMsgbox"
End Function
Damit der Benutzer auch die möglichen Konstanten per IntelliSense vorgesetzt bekommt, deklarieren Sie den Parameter Buttons einfach als VbMsgBoxStyle – das ist der gleiche Datentyp (eine Enumeration), der auch von der Original-MsgBox-Anweisung verwendet wird (siehe Bild 3).
Der Hintergrund, warum das MsgBox-Formular mit dem Parameter WindowMode:=acDialog aufgerufen werden soll, ist folgender: Erstens soll das Formular wie das Original den Fokus erhalten und den Zugriff auf die anderen Elemente der Anwendung verhindern, solange es geöffnet ist.
Und zweitens gibt es ja einen Antwortwert: die durch den Benutzer angeklickte Schaltfläche, die von der MsgBox-Funktion ausgewertet und zurückgegeben werden muss.
Und damit kommen wir direkt zur Funktion des Meldungsfenster-Formulars selbst: Die Schaltflächen sollen es nämlich nicht schließen, sondern nur unsichtbar machen, damit die aufrufende Funktion noch die gedrückte Schaltfläche ermitteln kann.
Funktionen des Meldungsfenster-Formulars
Der Großteil der Funktionen des Meldungsfensters läuft beim öffnen des Formulars ab. Ist es nämlich einmal mit dem richtigen Symbol, den Texten und den passenden Schaltflächen bestückt, braucht es nur noch das Anklicken einer der Schaltflächen durch den Benutzer auszuwerten.
Die Routine, die durch das Ereignis Beim öffnen des Formulars ausgelöst wird, ist dementsprechend relativ lang. Sie können diese in der Beispieldatenbank in voller Länge begutachten. Im Folgenden beschreiben wir die einzelnen darin enthaltenen Funktionen.
öffnungsargumente auseinandernehmen
Die erste Aufgabe ist es, die in einem zusammengesetzten Ausdruck und durch das Pipe-Zeichen (|) getrennten Parameter auseinanderzunehmen und entsprechenden Variablen zuzuordnen. Dazu schreibt die Routine zunächst die in der Eigenschaft OpenArgs des Formulars enthaltene Zeichenkette in eine passende Variable:
Dim strOpenArgs As String
strOpenArgs = CStr(Nz(Me.OpenArgs))
Es kann passieren, dass ein Benutzer das Formular frmMsgBox direkt aus dem Datenbankfenster heraus aufruft. In dem Fall wird kein öffnungsargument übergeben, was auf einfache Weise ermöglicht, das Formular erst gar nicht anzuzeigen:
If Len(strOpenArgs) = 0 Then
Cancel = True
Exit Sub
End If
Dabei fragt die obige Bedingung einfach ab, ob strOpenArgs einen Wert (Variant) mit einer Länge größer 0 enthält und bricht in diesem Fall den öffnungsvorgang ab; in allen anderen Fällen läuft die Routine weiter.
Die drei folgenden Variablen nehmen direkt anschließend die einzelnen Bestandteile des öffnungsarguments auf:
Dim MsgConst As VbMsgBoxStyle
Dim strMsg As String
Dim strTitle As String
Beachten Sie, dass MsgConst wie bereits im Funktionsparameter von MsgBox den Datentyp VbMsgBoxStyle (Long) hat.
Beim Auseinandernehmen des öffnungsarguments hilft dann die Split-Funktion, die eine Zeichenkette an einem Trennzeichen – hier am Pipe-Zeichen – teilt und in ein Array schreibt. Dieses wird hier gar nicht erst gespeichert, sondern direkt über die jeweilige Elementnummer (0, 1 und 2) referenziert und in die passenden Variablen geschrieben:
MsgConst = Val(Split(strOA, "|")(0))
strMsg = CStr(Split(strOA, "|")(1))
strTitle = Split(strOA, "|")(2)
überschrift oder nicht
Der nächste interessante Punkt ist, ob der Benutzer eine überschrift in seinem Meldungsfenster haben möchte. Dazu muss er, wie weiter oben erwähnt und auch im Original-Meldungsfenster bis Access 97 möglich, die überschrift durch ein At-Zeichen (@) vom Rest des Meldungstextes trennen. Dies geschieht, indem zunächst eine Variable die Position eines eventuell vorhandenen @ speichert:
Dim intPosSplitter As Integer
intPosSplitter = InStr(1, strMsg, "@")
Die InStr-Funktion liefert in dem Fall einen Wert größer 0 zurück, was sich folgende If…Then-Abfrage zu Nutze macht (ist der Wert 0, folgt Plan B: keine überschrift!). Dort landen die einzelnen Bestandteile dann in den String-Variablen strHeader und strText. Behandelt werden die Zeichenketten allerdings zuvor auch noch, und zwar durch die Funktion NarrowText (s. Beitrag Zeichenketten zerkleinern, Shortlink 560). Diese teilt die Zeichenkette in jeweils maximal 80 Zeichen lange Stücke auf. Und zusätzlich, damit die Freunde der alten MsgBox-Funktion von Access 97 vollends zu ihrem Recht kommen, werden im eigentlichen Meldungstext weitere @-Zeichen zu Zeilenumbrüchen inklusive Leerzeile umgeformt:
intPosSplitter = InStr(1, strMsg, "@")
If intPosSplitter > 0 Then
strHeader = NarrowText(CStr(Split(strMsg, _
"@")(0)))
Was bei der überschrift noch leicht war, nämlich einfach den Teil der Meldung vor dem ersten @-Zeichen auszulesen, wird beim folgenden Teil schon schwieriger, denn es können ja noch beliebig viele @-Zeichen folgen und entsprechende Zeilenumbrüche markieren.
Dem wird die folgende For…Next-Schleife gerecht, die alle Elemente des Arrays durchläuft, das durch die Split-Funktion erzeugt wird – bis auf eines, nämlich das erste. Das wurde ja bereits für die überschrift abgezweigt:
For i = LBound(Split(strMsg, "@")) + 1 _
To UBound(Split(strMsg, "@"))
strText = strText & Split(strMsg, "@")(i) _
& vbCrLf
Next i
Der so gewonnene Text enthält mindestens ein abschließendes Zeilenumbruchzeichen. Die folgende Do While-Schleife entfernt eines oder mehrere Zeilenumbruchzeichen am Ende der Zeichenkette:
Do While Right(strText, 2) = Chr(13) & Chr(10)
strText = Mid(strText, 1, Len(strText) - 2)
Loop
Schließlich wird der Text noch zurechtgestutzt, was die Funktion NarrowText erledigt:
strText = NarrowText(strText)
Die extrahierten Texte für die überschrift werden dann dem Steuerelement lblHeader zugewiesen; gleichzeitig wird dieses sichtbar gemacht (die Zuweisung des Textes an das Bezeichnungsfeld lblText folgt später):
Me!lblHeader.Visible = True
Me!lblHeader.Caption = strHeader
Sollte der Meldungstext kein @-Zeichen enthalten, legt die Routine nur ein einfaches Meldungsfenster ohne überschrift an. Der Meldungstext wird dann einfach durch die Funktion NarrowText geschickt (das Zuweisen an das Beschriftungsfeld erfolgt außerhalb der If…Then-Bedingung):
strText = NarrowText(strMsg)
Me!lblHeader.Visible = False
Schließlich sorgt die folgende Anweisung im Anschluss an die If…Then-Bedingung dafür, dass auch der eigentliche Meldungstext im passenden Bezeichnungsfeld lblText erscheint:
Me!lblText.Caption = strText
Abmessungen der Textfelder
Durch unterschiedliche Textlängen kann es passieren, dass die Bezeichnungsfelder in ihrer ursprünglichen Höhe nicht ausreichen. In dem Fall sollen diese und natürlich auch das Formular an die benötigte Höhe angepasst werden. Wie aber erhält man die Höhe, die eine bestimmte Zeichenkette benötigt
Dazu verwenden wir die Funktion GetTextSize, die der Beitrag Platzbedarf für Texte ermitteln (Shortlink 562) beschreibt – sie liefert die x- und die y-Maße eines durch den angegebenen Text aufgespannten Vierecks.
Für die Ermittlung dieser Maße benötigen Sie die notwendigen Eigenschaften der Bezeichnungsfelder wie etwa Schriftart oder Schriftgröße, die in den folgenden Variablen gespeichert werden – je vier für die überschrift und den eigentlichen Meldungstext:
Dim strFontnameText As String
Dim lngFontsizeText As Long
Dim bolFontBoldText As Boolean
Dim bolFontItalicText As Boolean
Dim strFontnameHeader As String
Dim lngFontsizeHeader As Long
Dim bolFontBoldHeader As Boolean
Dim bolFontItalicHeader As Boolean
Diese Variablen werden mit den entsprechenden Eigenschaften der Steuerelemente gefüllt – hier nur für die Eigenschaften von lblHeader:
strFontnameHeader = Me!lblHeader.FontName
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo