Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Ihren XING-Kontakten zeigen

Diesen Beitrag Ihrem XING-Kontakten vorstellen

Diesen Beitrag auf Facebook teilen

Verwandte Beiträge:

Daten visualisieren mit HTML

Onlinehilfe mit dem HTML Help Workshop

TreeView-Elemente im Griff

Listenfeld und Details in einem Formular

Steuerelemente zur Laufzeit verschieben

Alle verwandten Beiträge ansehen ...

Bisherige Kommentare:

Noch keine Kommentare vorhanden.

Alle Kommentare ansehen oder Kommentar abgeben

Über den Autor:

Alexander Sascha Trowitzsch

Bitte nutzen Sie das XING-Profil nicht
für Fragen zum Artikel, sondern nur für
den Kontaktaustausch beziehungsweise
Projekt- oder Supportanfragen.

Zusammenfassung

Fügen Sie Ihrer Anwendung ein Steuerelement zum Bearbeiten von Texten im HTML-Format hinzu

Techniken

Webbrowser-Steuerelement, VBA, HTML

Voraussetzungen

Access 2000 und höher

Beispieldateien

htmlform.mdb

Shortlink

www.access-im-unternehmen.de/705

HTML-Editor-Steuerelement

Sascha Trowitzsch, Berlin

Eine Access-Textbox, in einem Formular an ein Memo-Feld gebunden, ist eine spröde Angelegenheit, wenn es darum geht, ihren Inhalt ansprechend zu gestalten. Denn alle Formatierungsmöglichkeiten beziehen sich immer nur auf das ganze Feld, den gesamten Text. Ein einzelnes Wort etwa fett hervorzuheben, ist nicht möglich. Erst mit Access 2007 kam Farbe ins Spiel und der Richtext-Modus für Textfelder hielt Einzug, über den man Texte rudimentär formatieren kann. In allen früheren Access-Versionen bleibt man für diesen Zweck jedoch auf Fremdsteuerelemente angewiesen.

Die Anforderung, Texte zu formatieren, stellt sich auch in Datenbanken oft. Es müssen nicht gleich komplette Dokumente sein, die mit einem Datensatz verknüpft sind - es reichen bereits die berüchtigten Notiz- und Anmerkungsfelder, die man gern für Zusatzinformationen in Formulare einbaut, damit der Anwender dort alles unterbringen kann, was nicht in das Raster der vorgegebenen Eingabefelder passt.

Von dieser Möglichkeit wird dann erfahrungsgemäß auch reichlich Gebrauch gemacht, was nicht selten zu unübersichtlichen Textwüsten führt. Dabei würde nur wenig Formatierung bereits ausreichen, um eine gegliederte Darstellung des Textes zu ermöglichen.

In der Regel kommt ein Richtext-ActiveX-Steuerelement (richtx32.ocx) zum Einsatz, um dem Mangel abzuhelfen. Abgesehen davon jedoch, dass der Entwickler dann noch viel Arbeit vor sich hat, um das Steuerelement zusätzlich etwa mit einer Symbolleiste auszustatten, die es dem Anwender ermöglicht, den Text komfortabel zu editieren, kommen hier mindestens zwei Probleme ins Spiel.

Einmal ist das entsprechende OCX von Microsoft eigentlich nicht frei erhältlich, sondern entweder mit der Developer Edition von Access gebundelt, oder mit verschiedenen Entwicklungsumgebungen, wie Visual Basic 6.

Allerdings gibt es auch freie Alternativen, wie etwa das Steuerelement von Stephen Lebans oder das von vbAccelerator [1]. Zweitens muss man solch ein OCX mit der Datenbank weitergeben und ruft im Zweifelsfall Scherereien mit seiner Registrierung und den Verweisen im VBA-Projekt hervor.

Microsoft wurde sich dieser Unzulänglichkeit zum Formatieren offenbar bewusst und stellte mit Access 2007 den sogenannten Richtext-Modus für Textboxen bereit.

Unter der Voraussetzung, dass ein Memofeld einer Tabelle als Datenherkunft des Steuerelements dient, das seinerseits bereits in den Richtext-Modus versetzt wurde, kann in einer beliebigen Textbox der Inhalt über eine Popup-Toolbar formatiert werden (Abb. 1).

A2007_toolbar.png

Abb. 1: Textformatierung in Access 2007 (Richtext) über Popup-Toolbar

Leider ist dieses Popup-Menü, das nur beim Markieren von Text erscheint, auch schon die einzige Möglichkeit, auf die Formatierung des Textes Einfluss zu nehmen, und seine Bedienung erfordert etwas Geschicklichkeit im Umgang mit der Maus. Eine programmgesteuerte Einflussnahme ist nicht gegeben und das Menü lässt sich auch nicht abschalten.

Intern wird die Formatierung dann über HTML-Tags gespeichert, weshalb die Bezeichnung Richtext irreführend ist. Theoretisch ist es möglich, diese HTML-Tags anschließend über VBA-Code zu verändern.

Indessen darf man allerdings nicht erwarten, dass im Richtext-Modus nun beliebige HTML-Auszeichnungen genauso angezeigt würden, wie in einem Webbrowser; die Access 2007-Textbox beherrscht tatsächlich nur jene, die sich auch über das Popup-Menü erzeugen lassen.

Genügend Gründe also, sich nicht nur für die Versionen vor Access 2007 Gedanken über alternative Lösungen zu machen ...

Webbrowser-Steuerelement

Das Microsoft Webbrowser Control, welches Sie über die Liste der ActiveX-Steuerelemente in ein Formular einfügen können, stellt einen Mini-Browser für HTML-Dokumente bereit. Im kommenden Access 2010 wird ein solches Steuerelement übrigens standardmäßig zur Bordausstattung von Access gehören.

Es hat dort den Vorteil, sich direkt an ein Memofeld einer Tabelle binden zu lassen, was mit dem normalen Webbrowser-ActiveX zwar nicht möglich ist, uns andererseits aber, wie später noch ausgeführt wird, nicht gerade vor weltbewegende Programmierprobleme stellt.

Das Webbrowser-Steuerelement hat den entscheidenden Vorteil, dass es grundsätzlich auf jedem Windows-System vorhanden ist und mit der Installation von Access oder Office gar nichts zu tun hat. Der Internet-Explorer selbst stellt es zur Verfügung. Verweis- oder Registrierungsprobleme gibt es hier nicht.

Das Steuerelement ist tatsächlich identisch mit dem Anzeigebereich des Internet-Explorers und lässt sich daher auch auf gleiche Weise über dessen Objektmodell MSHTML, auch DOM genannt, steuern.

Dieses Document Object Model ist enorm umfangreich und leistungsfähig. Entwickler, die auch Webseiten mit Javascript erstellen, werden das wissen. Man kann auf jegliches Element eines HTML-Dokumentes sowohl zugreifen und dessen Eigenschaften ändern oder Aktionen darauf ausführen, wie auch neue Elemente erzeugen.

Stellen wir also fest, dass mit dem Webbrowser Control ein geeignetes und unkompliziertes Steuerelement bereitsteht, mit dem durchformatierter Text angezeigt werden kann.

Wie aber können wir den in diesem Steuerelement angezeigten Text editieren - der Internet Explorer bietet ja selbst auch keine Möglichkeit für manuelle Änderungen?

Webbrowser im Design-Mode

Die Tatsache, dass sich der Internet-Explorer mit nur einer Codezeile in einen Modus versetzen lässt, der das Dokument bearbeitbar macht, ist nur wenig bekannt.

Dabei kann Text nicht nur gelöscht oder hinzugefügt, sondern es können auch ohne viel Aufwand Formatierungen verändert werden. Der "echte" Internet-Explorer birgt aber natürlich keine Steuer- oder Menüelemente, über die sich das realisieren ließe. Mit wenigen Zeilen VBA erwecken wir jedoch das Webbrowser-Steuerelement unter Access zum Leben, wie die folgende Anleitung zeigt:

  • Erstellen Sie ein neues Formular unter einer beliebigen Access-Version.
  • Fügen Sie im Formularentwurf über die Menüleiste (Einfügen|ActiveX-Steuerelement...) oder über das Ribbon (Entwurf|Steuerelemente), ein Microsoft Webbrowser-Steuerelement ein und nennen es ctlHTML.
  • Versionsabhängig: Bevor Sie das Formular speichern, sollten Sie das Steuerelement in Access-Versionen vor Access 2003 auf seine endgültigen Abmessungen bringen. Leider ist es in früheren Versionen nicht möglich, die Größe des Elements nachträglich zu ändern - weder im Entwurf noch zur Laufzeit. Zwar lässt sich durchaus der Container-Rahmen ändern, der enthaltene Browser zeigt sich davon jedoch unbeeindruckt und behält seine einmal gespeicherte Größe bei.
  • Schreiben Sie in die Form_Load-Ereignisprozedur (Beim Laden) folgende Zeile:

Me!ctlHTML.Object.Navigate2 "http://www.access-im-unternehmen.de"

Nach dem Öffnen des Formulars zeigt dieses die gewünschte Webseite an. Die Navigate2-Methode ist dafür verantwortlich und erledigt das Gleiche, wie die Eingabe einer URL in die Adresszeile des Internet-Browsers.

Unser Ziel ist es jedoch nicht, eine x-beliebige Webseite anzuzeigen, sondern neue HTML-Dokumente zu erzeugen und mit HTML-Strings aus einem Tabellenfeld zu speisen. Um ein solches neues Dokument im Steuerelement aufzubauen, reicht diese einfache Anweisung:

Me!ctlHTML.Object.Navigate2 "about:blank"

Diese Zeile ist unbedingt erforderlich, denn ohne sie zeigt das Steuerelement schlicht eine weiße Fläche an. Erst ein Rechtsklick zur Laufzeit offenbart den Unterschied: Mit about:blank gibt es ein Kontextmenü, ohne gibt es keines.

Wählen Sie im Kontextmenü dann den Eintrag Quelltext anzeigen, tritt dieser Inhalt zutage: <HTML></HTML> und manchmal auch <BODY></BODY>.

Jetzt wird es interessant. Wie kann man das neue HTML-Dokument mit weiterem Inhalt, etwa aus einer Tabelle, füllen?

Auch das lässt sich erstaunlich einfach realisieren: Man schreibt den HTML-Text über die write-Methode des Dokuments. Zuvor aber noch ein kurzer Ausflug in das DOM-Modell.

DOM und MSHTML

Auf das Webbrowser-Steuerelement selbst haben Sie, wie oben angeführt, über dessen Object-Eigenschaft Zugriff.

Öffnen Sie im VBA-Editor den Objektkatalog, so finden Sie dort unter der Bibliothek SHDocVw, auf welche automatisch beim Einfügen eines Webbrowser-Controls verwiesen wird, das Klassenmodell zum Steuerelement. Die Klasse, die dem Control entspricht, nennt sich hier Webbrowser.

Sie zeigt allerlei Eigenschaften und Methoden, mit denen sich etwa die Gestalt des Steuerelements selbst einstellen lässt - unter anderem die bereits erwähnte Navigate2-Methode. Augenscheinlich findet sich jedoch nichts, was einen direkten Bezug zum HTML-Inhalt des gehosteten Dokuments hätte.

Die Bibliothek enthält derlei tatsächlich nicht. Dafür ist eine andere Bibliothek zuständig, die Sie manuell in die Verweise aufnehmen sollten und die ebenfalls vom Internet-Explorer-System bereitgestellt wird: MSHTML.

Öffnen Sie die Liste der Verweise (VBA-Editor, Menü Extras|Verweise...) und aktivieren Sie die Bibliothek Microsoft HTML Object Library.

Wenn Sie sich diese Bibliothek im Objektkatalog zu Gemüte führen, dann steht vermutlich die Frage im Raum, wie deren erschlagender Umfang von Klassen zu bändigen sei und wie die Verbindung zwischen dem Webbrowser-Control und der MSHTML-Bibliothek zustande kommt.

Das geschieht über genau eine Eigenschaft des Web-Controls, nämlich Document. Diese gibt ein Objekt der MSHTML-Klasse HTMLDocument zurück, welche im Grunde die oberste Ebene des DOM-Modells darstellt. Ein HTMLDocument enthält dann zahlreiche Unterobjekte, die ihrerseits haufenweise Eigenschaften und Auflistungen beheimaten. Nur ein exemplarisches Beispiel:

Das HTMLDocument enthält eine body-Eigenschaft, welche ein HTMLBody-Objekt zurückgibt. Das HTMLBody-Objekt kennt eine style-Eigenschaft in Form der HTMLStyle-Klasse. HTMLStyle wiederum zeigt eine Eigenschaft fontSize, die die Schriftgröße einstellt oder zurückgibt.

Wollten wir also die Schriftgröße des gesamten Bodys eines im Webcontrol geladenen Dokuments auf 11pt setzen, so ließe sich das auch ohne MSHTML über folgenden Ausdruck erledigen:

Me!ctlHTML.Object.Document.body.style.fontSize = "11pt"

Hier wird deutlich, dass der Verzicht auf die MSHTML-Bibliothek zu sehr langen Ausdrücken und zur Unübersichtlichkeit führt.

Einfacher ist es, wenn man das Dokument direkt einer Objektvariablen zuweist und dann alle weiteren Aktionen mit deren Hilfe ausführt:

Dim objDoc As MSHTML.HTMLDocument

Set objDoc = Me!ctlHTML.Document

With objDoc

    .body.style.fontSize = "11pt"

End With

Eine Alternative wäre auch dieser Code:

Dim objDoc As HTMLDocument

Dim objBody As HTMLBody

Set objDoc = Me!ctlHTML.Document

Set objBody = objDoc.body

With objBody

    .style.fontSize = "11pt"

    .style.font = "Arial"

End With

Dies soll lediglich verdeutlichen, wie verschachtelt das DOM-Modell ist und wie man mithilfe von Objektvariablen mehr Struktur in den Code bringen kann.

Völlig unverzichtbar wird MSHTML, wenn man auf Ereignisse reagieren will. Ein Objekt des Typs HTMLDocument etwa kann fast 40 Ereignisse auslösen.

Markiert man beispielsweise im angezeigten Dokument eine Passage, so löst dies ein Ereignis onselectionchange aus. Um auf dieses reagieren zu können, benötigt man eine Objektvariable mit dem Zusatz WithEvents:

Private WithEvents objDoc As MSHTML.HTMLDocument

...

Set objDoc = Me!ctlHTML.Document

...

Private Sub objDoc_onselectionchange()

    Debug.Print " Textauswahl wurde geändert"

End Sub

Die komplette Referenz zu DOM und MSHTML finden Sie unter [3] im Internet. An dieser Stelle soll es bei den wenigen grundsätzlichen Anregungen zur Arbeit mit der Bibliothek bleiben. Notiz am Rande: Die MSHTML-Bibliothek erweitert sich ständig im selbem Maße wie der Internet-Explorer.

Deshalb finden sich in der aktuellen Version etwa auch Klassen zum Phishing darin. Das gibt es aber erst seit Version 7. Wenn Sie mit der Bibliothek arbeiten, sollten Sie folglich genau darauf achten, dass keine Methoden Anwendung finden, die es auf einem etwaigen Zielsystem noch gar nicht gibt, weil dort vielleicht noch der Internet Explorer 6 installiert ist.

In der Referenz zu MSHTML ist jeweils angegeben, seit welcher Version eine Methode gültig ist.

HTML-Dokument bearbeiten

Kommen wir zur ursprünglichen Aufgabe zurück, ein Dokument im Web-Control in den bearbeitbaren Zustand zu versetzen.

Bisher sehen Sie nach dem Laden eines Dokuments über about:blank ja nur eine leere Fläche. Mit einer weiteren Zeile schreiben Sie nun HTML-Code hinein:

Dim strHTML As String

strHTML = "<body><strong>TEST</strong></body>"

ctlHTML.Document.write strHTML

Und schon erscheint die Ausgabe TEST im Steuerelement. Falls Sie hier auf die Idee kommen sollten, wie oben angeregt, eine Objektvariable einzusetzen, werden Sie keinen Erfolg haben:

Dim objDoc As HTMLDocument

Set objDoc = Me!ctlHTML.Document

objDoc.write strHTML

Dies führt zu einem Fehler, weil ausgerechnet die write-Methode von MSHTML.HTMLDocument nicht VBA-komform ist und als Parameter einen Variant-Typ vorsieht, den es unter VBA im Unterschied zu C++ nicht gibt.

Die Document.write-Methode - siehe oben - des Controls selbst hat damit aber offenbar keine Probleme und führt intern die notwendige Konvertierung durch.

Der hier hartkodierte Inhalt des Dokuments aus einer String-Variablen lässt sich selbstverständlich genauso gut aus einem Tabellenfeld auslesen, das wegen der möglichen Länge des Inhalts als Memofeld deklariert sein sollte. Im Formular könnte das mit nur einer Zeile so aussehen:

ctlHTML.Document.write Me!HTML_Memofeld.Value

Der Clou: Mit ebenfalls nur einer Zeile lässt sich das Dokument editierbar machen:

ctlHTML.Document.designMode = "On"

Nach dieser Anweisung können Sie den Cursor nun an eine beliebige Stelle im Dokument setzen und Text dazu schreiben oder löschen - gerade so, wie in einem Texteditor.

Den Inhalt des geänderten Dokuments lesen Sie anschließend aus dem Control aus und können ihn wieder im Datensatz speichern:

Me!HTML_Memofeld.Value = ctlHTML.Document.body.outerHTML

Hier wird nur der Body des Dokuments ausgelesen, aber mehr benötigen Sie auch nicht, weil das <HTML>-Tag ja bereits von einem neu per about:blank erzeugten Dokument angelegt wird. outerHTML bedeutet dabei, dass der HTML-Code inklusive des body-Tags und möglicher Attribute selbst zurückgegeben wird, während etwa innerHTML nur den eigentlichen Inhalt des Bodys enthielte.

Möchten Sie das Dokument schließlich wieder in den normalen Zustand versetzen, so schalten Sie den Design-Mode einfach wieder ab:

ctlHTML.Document.designMode = "Off"

Set objDoc = ctlHTML.Document

Wichtige Anmerkung dazu: Sollten Sie das Dokument einer Objektvariablen zugewiesen haben, so ist diese nach dem Ändern des Design-Modes in der Regel nicht mehr gültig. Sie sollten deshalb nach jedem Wechsel des Design-Modes die Zuweisung erneut vornehmen.

HTML-Dokument formatieren

Mit dem bisher Beschriebenen sind Sie in der Lage, im HTML-Dokument des Steuerelements Text hinzuzufügen oder zu löschen. Was nun noch fehlt ist die Möglichkeit, ihn zu formatieren.

Dazu ist es für die wichtigsten Funktionen gar nicht notwendig, die HTML-Auszeichnungen per Code zu modifizieren. Normalerweise muss ja ein Text mit Formatierungs-Tags versehen werden, damit er sich in veränderter Gestalt präsentiert.

So braucht es etwa das Tag <em>, um ein Wort fett wiederzugeben: <em>TEST</em>. Diese Tags muss man jedoch nicht in den HTML-Code hineinflicken, sondern bedient sich einer komfortablen Methode von MSHTML, die das automatisch macht, nämlich der Anweisung execCommand.

Diese Methode eines HTMLDocument-Objekts erwartet in der Regel lediglich einen Anweisungs-String als Parameter und wirkt sich dann auf die aktuelle Auswahl im Dokument aus. Um eine mit der Maus markierte Passage fett zu formatieren, setzen Sie diese Anweisung ab:

objDoc.execCommand "Bold"

Manchmal wird auch ein zusätzlicher Parameter benötigt, der neben der Formatierungsanweisung noch einen Wert übergibt, wie etwa beim Ändern der Schriftart:

objDoc.execCommand "Fontname", "Courier New"

Damit können Sie nun beispielsweise eine Schaltfläche mit der Aufschrift Fett versehen und in deren Click-Ereignisprozedur die Anweisung von oben schreiben. Sie erhalten somit einen einfachen WYSIWYG-HTML-Editor.

Eine gute Demo für einen solchen auf der execCommand-Methode beruhenden Editor unter Access finden Sie bei Stephen Lebans [2].

Wenn Sie erfahrem möchten, welche Kommandos die execCommand-Methode unterstützt und wie die genaue Syntax auszusehen hat, so finden Sie eine erschöpfende Zusammenstellung unter [4].

Nicht für jeden Zweck allerdings reicht diese Methode allein aus und der HTML-Code muss manchmal direkt modifiziert werden. Auch hier gibt es jedoch Unterstützung durch MSHTML in Gestalt der Anweisung pasteHTML.

Sie ersetzt den augenblicklich markierten Text durch einen im Parameter übergebenen HTML-Code. Das könnte etwa so aussehen:

objDoc. selection.createRange.pasteHTML "<em>TEST</em>"

Hier wird zunächst die aktuelle Auswahl im Dokument als selection-Objekt erhalten. Mit diesem selbst kann man aber noch nicht viel anfangen. Seine Funktion createRange erst gibt das markierte Element oder eine ganze Auflistung von Elementen zurück.

In der Regel wird das ein Objekt der MSHTML-Klasse IHTMLTxtRange sein. Und eben diese kennt die Methode pasteHTML, die genau dasselbe tut, als würden Sie HTML-Code aus der Zwischenablage ins Dokument einfügen. Die aktuelle Auswahl wird also durch den neuen HTML-Code ersetzt. Ist kein Text ausgewählt, so wird der HTML-String an jener Stelle eingefügt, an der sich der Cursor befindet.

Nun möchten Sie allerdings weniger einen komplett neuen HTML-Code einfügen, als vielmehr vorhandenen Text mit Formatierungs-Tags "umrahmen". Dazu muss im ersten Schritt der ausgewählte Text erhalten werden, was ebenfalls über das selection-Objekt möglich ist:

strHTML = objDoc.selection.createRange.Text

Nun kann der Text mit den gewünschten Formatierungs-Tags zusammengesetzt werden:

strHTML = "<em>" & strHTML & "</em>"

objDoc. selection.createRange.pasteHTML strHTML

Dieses Beispiel ist an sich überflüssig, da ja bereits die execCommand-Methode mit dem Parameter Bold zum gleichen Ergebnis führt. Es demonstriert aber die grundsätzliche Vorgehensweise auch für kompliziertere Operationen.

Sie möchten eventuell erfahren, wie ein im Dokument markiertes Wort formatiert ist?

Auch dazu reicht ein einzige Funktion aus, nämlich die queryCommandValue-Methode des selection-Objekts:

Wert = objDoc.selection.createRange.queryCommandValue ("Bold")

Hier wird abgefragt, ob die Auswahl fett formatiert ist. Der Ausdruck gibt True zurück, wenn das der Fall ist. Eine Rückgabe aller Formatierungen im Form eines Arrays oder einer Collection ist allerdings nicht möglich - es muss schon nach jeder möglichen Formatierung einzeln gefragt werden.

Die Rückgabe ist vom Datentyp Variant und kann je nach Kommando ein Bool-, Integer- oder String-Typ sein.

Nützlich ist das etwa, wenn Sie die Formatierung über den Zustand eines Formatierungs-Buttons signalisieren möchten. Die erwähnte Schaltfläche Fett könnte etwa als Umschaltfläche daher kommen und bei fett markiertem Text in gedrücktem Zustand erscheinen, so wie das auch in Textverarbeitungen geschieht.

Damit Ihre Anwendung erkennt, wann sich die aktuelle Markierung geändert hat und somit die Liste der Formatierungen erneut abgefragt werden muss, machen Sie sich das onselectionchange-Ereignis des HTMLDocument-Objekts zunutze. In dieser Ereignisprozedur ermitteln Sie einfach alle vorgesehenen Formatierungen und stellen den Zustand der Schaltflächen entsprechend ein.

Aber damit wären wir eigentlich schon bei der Beschreibung der Beispieldatenbank zu diesem Beitrag, die sich htmlform.mdb nennt und unter Access 2000 und höher lauffähig ist.

Datengebundenes HTML-Steuerelement

In Abb. 2 sehen Sie das Beispielformular der Anwendung htmlform.mdb, welches eine ziemlich einfache Adresskartei darstellt, gebunden an die Tabelle tblPersonen.

demo_form.png

Abb. 2: Formular der Beispieldatenbank mit formatierbarem Anmerkungenfeld

Neben den gängigen Datenfeldern ist ein Anmerkungen-Feld enthalten, dessen Inhalt sich wie in einer Textverarbeitung formatieren lässt - das Webbrowser-Steuerelement wird dafür verwendet.

Damit die Lösung allgemein verwendbar ist, kommt für dieses Feld ein Unterformular zum Einsatz, das auch den ganzen benötigten VBA-Code einhält. Sie können dieses Unterformular (sfrmHTML) auch in Ihre eigenen Anwendungen integrieren.

Was Sie dann noch mitimportieren müssen, ist das Modul mdl_sfrmHTML, welches einige Hilfsroutinen enthält, die leider nicht direkt in den Formular-Code aufgenommen werden könnten, weil API-Callbacks zur Enumeration der Schriftarten im System zum Einsatz kommen, die den Operator AddressOf erforderlich machen. Dieser Operator lässt sich nicht für Prozeduren in Klassenmodulen verwenden.

Daneben müssen in der Zielanwendung noch Verweise auf die MSHTML-Bibliothek sowie auf SHDocVw gesetzt sein. Diese Bibliothek finden Sie in der Liste der Verweise unter Microsoft Internet Controls; sie wird auch automatisch beim Einfügen eines Webbrowser Controls gesetzt.

Das Unterformular lässt sich dann wie ein eigenes Steuerelement einsetzen und an ein Datenfeld des Hauptformulars binden. Lediglich einige Eigenschaften des Unterformulars müssen eingestellt werden, alles Weitere läuft voll automatisch ab - später mehr dazu.

Im Rohzustand, aber edtierbar, zeigt sich das Unterformular wie in Abb. 3.

editmode_true.png

Abb. 3: HTML-Editor-Unterformular in unberührtem Zustand

Neben dem Webbrowser-Control zur Eingabe des Textes findet sich in der rechten oberen Ecke noch ein unscheinbarer Button, der zum Ein- und Ausschalten der Formatierungen-Toolbars dient. Ein Klick auf ihn, und schon ändert sich das Erscheinungsbild des Unterformulars wie in Abb. 4.

toolbar.png

Abb. 4: HTML-Editor mit eingeschalteter Toolbar zur Textformatierung

Sie können nun Text in das Webbrowser-Feld eingeben, Passagen markieren und Formatierungen über die Schaltflächen der Toolbar vornehmen, wie in Abb. 5.

edit_text.png

Abb. 5: HTML-Editor-Unterformular im Einsatz

Es wäre müßig, hier die Formatierungsmöglichkeiten im Einzelnen zu erläutern. Öffnen Sie einfach die Beispielanwendung und fahren Sie mit der Maus über die Schaltflächen der Toolbar - im erscheinenden Tipptext wird dann die Bedeutung des Buttons angezeigt.

Sie können selbstverständlich das Unterformular noch weiter aufbohren und mit zusätzlichen Möglichkeiten versehen, in der aktuellen Ausführung dürfte es jedoch den meisten Anforderungen gerecht werden - schließlich geht es hier um ein einfaches Pseudo-Textfeld, nicht um den Nachbau von MS Word.

Unter Access 2000 erhalten Sie beim Öffnen des Formulars möglicherweise eine Fehlermeldung, die vom Befüllen der Combobox mit den Schriftartennamen herrührt.

Dieses Kombinationsfeld ist auf Werteliste als Datenherkunft eingestellt und wird über eine Hilfsfunktion GetFonts mit einem semikolonseparierten String der Schriftartennamen bestückt.

Unter Access 2000 darf diese Werteliste nicht länger als 2.048 Zeichen lang sein, was hier schnell überschritten ist. Dafür ist in der Beispieldatenbank kein Workaround eingebaut.

Denkbar wäre etwa die Zuweisung einer Hilfstabelle an das Kombinationsfeld, die zuvor über die GetFonts-Prozedur mit den Fontsnamen befüllt wurde, also eine direkte Datenbindung der Combobox.

Auf einige Spezialitäten des Editor soll hier doch noch eingegangen werden.

Als Schriftgröße werden die Zahlen 1 bis 7 verwendet, was nicht etwa als Größe in Punkt zu verstehen ist, sondern die in HTML übliche Größenanweisung darstellt.

An sich lassen sich über Style-Angaben Schriftgrößen auch in Punkt angeben (style="font-size:11pt"), das würde dann aber wieder eine umfangreichere Programmierung erforderlich machen, weil die execCommand-Methode im Verein mit der Anweisung FontSize solche Angaben nicht erlaubt.

Ersatzweise müsste also das HTML über pasteHTML, wie oben bereits ausgeführt, modifiziert werden.

Hyperlinks werden erzeugt, indem man den gewünschten Text markiert und auf die Hyperlink-Schaltfläche klickt. Dabei öffnet sich eine Inputbox zur Eingabe der Zieladresse. Sie wird anschließend über das <a href>-Tag in den HTML-Code eingesetzt. Dieser Link funktioniert dann allerdings nicht im Design-Modus on.

Erst wenn der Bearbeitungsmodus abgeschaltet wird, reagiert der Mauszeiger auf den Link-Text. Wird der Link nun angeklickt, so öffnet sich die URL in einem externen Browser. Der Grund dafür ist sicher plausibel: Normalerweise würde das Webbrowser-Control selbstständig zur gewünschten URL navigieren.

Dann aber hätte man statt des editierten Textes ganz anderen Inhalt im Control und würde diesen unter Umständen fälschlicherweise abspeichern. Auch ein Zurück zum vorigen per write-Methode angelegten Text ist nicht möglich - dieser schwebt bereits im Nirvana.

Um das Navigieren zur Link-Adresse zu unterbinden, wird dieser Vorgang abgefangen. Dazu kann man sich des BeforeNavigate-Ereignisses des Webbrowser-Controls bedienen. Das Ereignis gibt als Parameter unter anderem die URL an, zu der das Control navigieren möchte, und einen Parameter Cancel, der den Vorgang dann abbricht, wenn er in der Ereignisprozedur auf True gesetzt wird.

Die entsprechende Prozedur des Unterformulars vergleicht nun, ob es sich bei der Link-Adresse um about:blank handelt, also das eigene Dokument, oder um einen externen Link. In letzterem Fall wird Cancel auf True gesetzt und stattdessen die Adresse einem externen Browser per Shellexecute übergeben.

Umbrüche sind ein spezielles Thema in HTML. Zwar entspricht die Eingabetaste, die zu einem <p>-Tag (paragraph) führt, schon dem gleichen Vorgang etwa unter Word.

Nur ist der Abstand der Absätze im Browser dann so groß, dass es wie eine Leerzeile wirkt. Deshalb wird im HTML-Unterformular das ENTER zu einem Zeilenumbruch gemacht (<br>) und die Kombination STRG-ENTER zu einem Absatzwechsel (<p>). Das kommt dem Verhalten gängiger Textverarbeitungen einfach näher.

Technisch ist die Sache ohnehin eine Speziallösung. Denn ein ActiveX-Steuerelement erhält unter Access die Eingabetaste grundsätzlich erst gar nicht mitgeteilt - auch dann nicht, wenn es den Fokus besitzt.

Warum Microsoft das so gestaltete, ist unklar. Deshalb ist es notwendig, im Formular die Tastenvorschau-Eigenschaft auf Ja zu stellen und alle KeyDown-Events abzufangen. Alle Tasten-Codes bleiben unberührt bis auf den Wert 13, der die ENTER-Taste identifiziert.

Sobald dieser auftaucht, wird dem Dokument je nach möglichem Zustand der Kontrolltasten ein <br> oder ein Absatzwechsel verpasst - Letzteres über die execCommand-Methode InsertParagraph.

Hier unterscheidet sich die Lösung übrigens deutlich von jener, die Stephen Lebans in seiner Demo verbaute. Stephen fängt zwar ebenfalls die ENTER-Taste ab, ermittelt dann aber etwas umständlich per API das Browser-Fenster-Handle, um ihm dann mit SendKeys die Tastencodes zu senden - eine in meinen Augen unnötige Verrenkung.

In der Toolbar des Unterformulars ist eine Schaltfläche mit einem Häkchen zu finden, die das Speichern des HTML-Inhalts in den Datensatz des Hauptformulars erwirkt. Eigentlich wäre dies überflüssig, denn bereits das Verlassen des HTML-Unterformulars zieht explizit dasselbe nach sich.

Da die Schaltfläche aber beim Webcontrol auch den Design-Modus abschaltet, ist eine Kontrolle des Ergebnisses möglich, solange man sich noch im Unterformular befindet.

Das Seitenlayout im Browser ändert sich nämlich teilweise etwas (Umbrüche!), wenn man zwischen beiden Modi umschaltet - zumindest lässt sich das beim Internet-Explorer 8 feststellen.

Code-Fragmente

Wie das HTML-Unterformular eingesetzt werden kann, sehen Sie am Formular frmPersonen der Beispieldatenbank htmlform.mdb. In seiner Load-Prozedur werden alle Einstellungen für die Unterformularklasse vorgenommen:

With Me!sfrmAnmerkungen.Form

    .BoundField = "Anmerkungen"

    Set .ParentControl = Me!sfrmAnmerkungen

    .BackColor = Me.Section(acDetail).BackColor

    .ToolbarTimeout = 0

    .AllowEditMode = False

End With

Die wichtigste öffentliche Property ist BoundField. Ihr übergibt man den Namen des Tabellen- oder Abfragefeldes, an das man den HTML-Text binden möchte. Im Beispiel ist dies das Memo-Feld Anmerkungen der Formulartabelle tblPersonen.

Weiter ist zwingend der Name des Unterformulars selbst in ParentControl anzugeben, damit die Unterformularklasse dessen Ereignisse Beim Hineingehen und Beim Verlassen abfangen kann, um darauf mit dem Wechsel des Design-Modus reagieren zu können. (Offenbar gibt es aus einem Unterformular heraus keinen einfachen Weg, den Steuerelementnamen zu ermitteln, unter dem es im Hauptformular eingesetzt ist.)

Mit BackColor kann man optional die Hintergrundfarbe für die Toolbar bestimmen. Im Beispiel wird dafür die gleiche Farbe genommen, die auch der Detailbereich aufweist.

ToolbarTimeout ist ein Long-Wert, der angibt, nach welcher Zeitspanne (in Millisekunden) sich die Toolbar automatisch ausblendet, wenn im HTML-Unterformular nichts passiert.

Wird er, wie im Beispiel, auf 0 gesetzt, so bleibt der Toolbar dauerhaft sichtbar.

AllowEditMode bestimmt, ob der Text im Steuerelement überhaupt bearbeitbar sein darf. Wird hier False zugewiesen, wie oben, dann erscheint die Formatierungs-Toolbar erst gar nicht und die HTML-Anzeige befindet sich quasi im Readonly-Modus.

Die Eigenschaft kann aber jederzeit neu gesetzt werden, was im Beispielformular dann geschieht, wenn der Button mit der Aufschrift Bearbeiten ausgelöst wird (cmdEdit_Click). Die Toolbar erscheint nun automatisch und der Design-Mode ist eingeschaltet.

Im Form_Resize-Event wird das HTML-Unterformular auf brauchbare Breite und Höhe gebracht, sodass es immer den unteren Teil des Hauptformulars ausfüllt:

With Me!sfrmAnmerkungen

    .Width = Me.InsideWidth - 600

    .Height = Me.InsideHeight -.Top - 120

End With

Unter Access 2007 kann man diesen Teil weglassen und stattdessen das Unterformular mit den Eigenschaften Horizontaler Anker und Vertikaler Anker verankern.

Unter Access 2000 funktioniert, wie erwähnt, zwar die Größenänderung für das Unterformular und das integrierte Webcontrol, der darin enthaltene Browser verbleibt jedoch in seinen einmal gespeicherten Abmessungen. Dafür gibt es bisher keine bekannte Lösung. Zwar kann er mit API-Funktionen vergrößert werden, funktioniert dann aber nicht mehr korrekt. Das bedeutet, dass unter Access 2000 das HTML-Unterformular eine feste Größe haben muss und man die Resize-Prozedur auskommentieren kann.

Wenn Sie im Web-Control ein neues Dokument anlegen (about:blank) oder zu einer neuen Seite navigieren (Navigate2), dann ist es zunächst mit dieser Aufgabe beschäftigt, das jedoch in einem eigenen Thread, weshalb der VBA-Code sofort fortfährt. Auf den Inhalt des Controls, also das Document-Objekt, können Sie aber erst zugreifen, wenn der Vorgang abgeschlossen ist. Zum Glück gibt es eine Status-Eigenschaft im Web-Control, die Auskunft darüber gibt, ob ein Dokument fertig geladen ist, sodass man sie in einer Schleife abfragen kann:

Sub WaitForReady(Optional lState As Long = _

    READYSTATE_INTERACTIVE)

    If objHTML Is Nothing Then Exit Sub

    Do

        DoEvents

    Loop Until objHTML.ReadyState >= lState

End Sub

Diese Hilfsprozedur wird erst verlassen, wenn der gewünschte ReadyState erreicht ist. Gültig ist das Dokument in der Regel dann, wenn der Status READYSTATE_INTERACTIVE = 3 entspricht. Diese Prozedur wird an verschiedenen Stellen im HTML-Unterformularcode aufgerufen.

In der Toolbar von sfrmHTML finden Sie einen Button, durch den ein Rahmen um die im Dokument markierte Passage gezogen wird. Dabei wird nicht etwa eine Tabelle angelegt, sondern per Style-Eigenschaft ein border-Attribut gesetzt (Prozedur cmdFrame_Click). Derlei lässt sich nicht per execCommand bewerkstelligen, sondern muss durch Modifikation des HTML-Codes erfolgen:

objDoc.selection.createRange.pasteHTML _

"<span style=""border-width:1px;border-style:solid"">" _

objDoc.selection.createRange.Text & "</span>"

Hier wird der Text mit einem SPAN-Tag umrahmt und dessen Style mit einem border-Attribut versehen. Damit taucht ein kleines Problem auf: Diese Formatierung kann nicht über die Funktion queryCommandValue abgefragt werden. Die entsprechende Umschaltfläche wird also nicht aktiv, wenn man später die Markierung auf diesen Bereich setzt. Auch das Entfernen der Formatierung (cmdDelFormat_Click) klappt damit nicht mehr. In diesem Fall hilft nur das Löschen der kompletten Textpassage und Neueingabe.

Wollte man diesen Umstand ändern, so wäre einiges mehr an Programmierung nötig. Der HTML-Code des selection-Objekts müsste analysiert und das SPAN-Tag daraus gelöscht werden. Den HTML-Code der markierten Stelle erhalten Sie mit dieser Anweisung:

strHTML = objDoc.selection.createRange.htmlText

Schrift- und Hintergrundfarbe des ausgewählten Bereichs können mit Klick auf die dafür vorgesehenen Toolbar-Elemente geändert werden.

Es handelt sich dabei nicht um Schaltflächen, sondern um Bildsteuerelemente, deren Click-Prozedur zum Aufruf des per API erzeugten Farbauswahldialogs von Windows führt (mdl_sfrmHTML). Der Farbwert, den dieser Dialog zurückgibt, ist ein RGB-Long-Wert, der für HTML erst in die im Web übliche Hexadezimal-Syntax überführt werden muss, was über die Hilfsroutine MakeColorCode geschieht:

Function MakeColorCode(AColor As Long) As String

    Dim strColor As String

    strColor = Hex(AColor)

    strColor = String(6 - Len(strColor), "0") & strColor

    strColor = Mid(strColor, 5) & Mid(strColor, 3, 2) & Left(strColor, 2)

    MakeColorCode = "#" & strColor

End Function

Der Wert für Rosa (13158655) wird so zu #FFC8C8.

Beim Wechsel eines Datensatzes im Hauptformular soll dem Web-Control der neue Inhalt des zugehörigen Tabellenfeldes zugewiesen werden. Damit das Unterformular diesen Wechsel überhaupt mitbekommt, muss es auf das Current-Ereignis des Hauptformulars reagieren.

Zwar könnte man gleich im Hauptformular und dessen Current-Ereignis den dafür benötigten Code platzieren, müsste ihn dann aber in jedem Formular wiederholen, welches ein HTML-Unterformular hostet. Um hier unabhängiger zu bleiben, wurde dieser Code in das Unterformular integriert.

Dafür ist ein Verweis auf das Hauptformular in Form der per WithEvents deklarierten Objektvariablen frmParent vorgesehen. Deren Current-Ereignis wird aber nur ausgelöst, wenn die zugehörige Ereigniseigenschaft auch aktiviert ist:

frmParent.OnCurrent = "[Event Procedure]"

Die Ereignis-Routine sieht dann so aus:

Private Sub frmParent_Current()

    Dim strHTML As String

    objHTML.Navigate2 "about:blank"

    WaitForReady

    If Not frmParent.NewRecord Then

        strHTML = Nz(frmParent.Controls(m_Field))

    End If

    If Len(strHTML) > 0 Then

        objHTML.Document.write strHTML

    End If

    Set objDoc = objHTML.Document

End Sub

Als Erstes wird ein neues Dokument im Control über about:blank angelegt und auf dessen Gültigkeit mit der besprochenen Hilfsfunktion WaitForReady gewartet. Dann wird, falls es sich nicht um einen neuen Hauptdatensatz handelt (NewRecord-Eigenschaft), der Inhalt des Tabellenfeldes ausgelesen. Um welches Feld es sich dabei handelt, wurde zuvor beim Initialisieren des Unterformulars als String in der Membervariablen m_Field abgelegt. Schließlich wird der HTML-Text mit der write-Methode in das Dokument geschrieben und ein Verweis auf das nun fertige Dokument in der Objektvariablen objDoc abgelegt, die nun für weitere Verwendung und Formatierungen zur Verfügung steht.

Der Code für den umgekehrten Vorgang, das Auslesen des Dokuments und Speichern im Tabellen-feld, wird ausgeführt, sobald das Unterformular verlassen wird, was über ein ebenfalls abgefangenes Ereignis geschieht:

Private Sub ctlParent_Exit(Cancel As Integer)

    Dim strHTML As String

    strHTML = objDoc.body.outerHTML

    If m_AllowEdit Then _

        frmParent.Controls(m_Field).Value = strHTML

        objDoc.designMode = "Off"

    End Sub

Aus der Dokumentvariablen wird über die body.outerHTML-Eigenschaft der HTML-Text ermittelt und nur dann in das Tabellenfeld gespeichert, wenn dies über die Eigenschaft AllowEditMode erlaubt wurde. Anschließend wird im Browser-Control der Bearbeitungsmodus abgeschaltet.

Zusammenfassung

Über das immer verfügbare Webbrowser-Control wird die Möglichkeit geschaffen, Texte unter Access formatierbar zu machen. Die vorgestellte Lösung über ein HTML-Unterformular lässt sich leicht in beliebige eigene Datenbanken übertragen.

Für den Produktiveinsatz sollten Sie sich allerdings den Code genauer ansehen. Möglicherweise benötigen Sie nicht alle der enthaltenen Formatierungsanweisungen oder Sie möchten vielleicht das Verhalten der ENTER-Taste ändern.

Die Fehlerbehandlung im Klassenmodul ist auch nur ziemlich rudimentär gestaltet, weshalb gerade mal 350 Zeilen Code für das Projekt ausreichten. Trauen Sie sich und machen Sie Ihren eigenen Editor daraus!

Letzte Anmerkung: Versuchen Sie erst gar nicht, das Webbrowser-Control in einen Bericht einzubauen - es funktioniert nicht, und es gibt auch sonst kein ActiveX-Control, welches die Anzeige von HTML in Berichten leisten könne. Es bleibt nur der direkte Ausdruck des HTML-Dokuments, etwa über die execCommand-Methode Print.

Links

[1] Freie Richtext-ActiveX-Steuerelemente von Stephen Lebans und von vbAccelerator: http://www.lebans.com/richtext.htm, http://www.vbaccelerator.com/codelib/richedit/richedit.htm

[2] HTML-Editor-Demodatenbank von Stephen Lebans: http://www.lebans.com/htmleditor.htm

[3] Referenz zur Internet-Explorer-Programmierung von Microsoft: http://msdn.microsoft.com/en-us/library/aa752038%28VS.85%29.aspx

[4] Formatierung im Webbrowser per execCommand-Methode: http://msdn.microsoft.com/en-us/library/aa220275%28office.11%29.aspx

Download

Download

Die .zip-Datei enthält folgende Dateien (.mdb-Dateien mit '00' im Dateinamen funktionieren in Access 2000 und höher):

htmlform.zip

Beispieldateien downloaden

Verwandte Beiträge:

Daten visualisieren mit HTML

Onlinehilfe mit dem HTML Help Workshop

TreeView-Elemente im Griff

Listenfeld und Details in einem Formular

Steuerelemente zur Laufzeit verschieben

Modale Dialoge mal anders

Formulare im Blickpunkt

Zugriff auf Daten in Formularen und Steuerelementen

Zugriff auf Formulare

Das Optionsgruppen-Steuerelement

Registersteuerelemente von A-Z

Tipps und Tricks

Flexible Datumstextfelder

Formularposition speichern und wiederherstellen

Access 2007: Bilder und Schaltflächen

Kommentare und Ergänzungen

Wenn Sie Kommentare, Fragen oder Ergänzungen zu diesem Artikel haben, können Sie diese hier eintragen. Wir bemühen uns, kurzfristig auf Ihren Kommentar einzugehen.

Ihr Name:

Ihre E-Mail-Adresse (für
Rückfragen, wird nicht veröffentlicht:

Betreff:

Ihr Kommentar zu diesem Artikel:

© 2003-2010 André Minhorst Alle Rechte vorbehalten.