Es gibt zahlreiche Anwendungsbereiche für einen eingebetteten Webbrowser in Access-Formularen. Ob es um die statische Anzeige von HTML-Dateien geht, um dynamisch generierte Webseiten, die etwa Berichte ausgeben, oder um die Nutzung von Webservices. Microsoft hat dies erkannt und in Access 2010 das neue Webbrowser-Steuerelement eingeführt. Während es einfach ist, den Inhalt einer Webseite von VBA aus zu steuern, sei der Content nun durch Stringverkettung erzeugt oder über das DOM-Objektmodell des Browsers, wird es schwierig, von einer eingebetteten Webseite aus über Skripte auf Access und VBA zuzugreifen, um etwa Daten abzuholen. Wie das dennoch geht, finden Sie im Folgenden beschrieben.
Webbrowser-Steuerelemente
Bis zu Access 2010 ist es notwendig, den Internet Explorer als ActiveX-Steuerelement in ein Formular einzufügen. Über das Entwurfsmenü Einfügen|ActiveX-Steuerelement…|Microsoft Web Browser wird ein Browser-Fenster im Detailbereich angelegt. Der Internet Explorer, egal in welcher Version, stellt dieses Control von Haus aus zur Verfügung. Das Control hat also mit Access oder dessen Installation selbst nichts zu tun.
In Access 2010 bedient man sich der Steuerelementesammlung im Entwurfs-Ribbon und wählt das Webbrowser-Steuerelement aus (s. Bild 1).
Bild 1: Auswahl des Webbrowser-Steuerelements im Entwurf-Ribbon von Access 2010
Dieses neue Steuerelement ist im Grunde nichts anderes als ein Wrapper für das ActiveX-Control des Internet Explorers. Es weist somit weitgehend die gleichen Eigenschaften und Methoden auf. Der wesentliche Unterschied besteht darin, dass dieses Element sich direkt an ein Feld der Datenherkunft des Formulars binden lässt.
Dabei muss es sich um ein Textfeld handeln, das die URL der Seite enthält, zu welcher navigiert werden soll. HTML-Code kann man hier nicht direkt übergeben.
Dem ActiveX-Control hingegen muss man per VBA sagen, welche Seite es anzeigen soll. Dazu bedient man sich der Methode Navigate2 des Objekts:
Me!ctlWeb.Object.Navigate2 "about:blank"
In diesem Fall wird eine leere Webseite im Browser angelegt. Tatsächlich funktioniert dasselbe auch mit dem Webbrowser-Steuerelement von Access 2010, das diese Methode eigentlich gar nicht kennt.
Der feine Unterschied liegt hier in der Ansprache einmal des Steuerelements selbst (Me!ctlWeb) und davon abweichend des enthaltenen Steuerelements (Me!ctlWeb.Object). Das letztere Objekt stellt die Webbrowser-Klasse der Bibliothek ShDocVw dar, auf die automatisch ein Verweis im VBA-Projekt hinzugefügt wird – sowohl im Falle des ActiveX-Controls, wie auch beim Access 2010-Steuerelement. Damit stehen dann auch im Access 2010-Steuerelement dieselben Eigenschaften und Methoden des DOM-Objektmodells der MSHTML-Bibliothek zur Verfügung.
Meist wird man das Steuerelement im Formular so ausstatten, dass es die verfügbare Breite einnimmt. Bei veränderbaren Formularen ist es dann bis Access 2007 notwendig, im Resize-Ereignis des Formulars das Webbrowser-Steuerelement neu zu dimensionieren, indem man seine Eigenschaften Width und Height setzt.
Das klappt allerdings nur in Access 2003. In früheren Versionen ändert sich die einmal im gespeicherten Entwurf gesetzte Größe nicht und wird auf ewig beibehalten.
Unter Access 2007 und 2010 verwenden Sie dafür das Verankern-Feature (Tab Anordnen|Position|Anker) und stellen das Control etwa auf Nach unten und quer dehnen ein.
Web-Inhalte laden
Häufig werden Sie einfach nur eine Webseite im Internet darstellen wollen. Das Laden dieser Webseite erledigt wieder die Navigate2-Methode des Webbrowsers:
Me!ctlWeb.Object.Navigate2 "http://www.access-im-unternehmen.de"
Ebenso können Sie natürlich eine lokal im Dateisystem vorhandene HTML-Datei aufrufen. Als Parameter dient dann der ganz normale Pfad, wie sie ihn auch im Explorer angeben würden.
Interessant wird es, wenn Sie den Inhalt der Webseite dynamisch erzeugen möchten. Eine gängige Methode ist es, den HTML-Code dabei als String in VBA zusammenzusetzen, diesen lokal als Datei abzuspeichern und die Datei schließlich ins Webbrowser-Steuerelement zu laden. Dabei können etwa auch Inhalte aus Tabellen, die über Recordsets ausgelesen werden, zum Zuge kommen.
Einfacher, da ohne Umweg über das Dateisystem, kann dem Browser aber der Inhalt auch direkt zugewiesen werden. Dafür gibt es die write-Methode des geladenen Dokuments.
Der einzige Grund, das Dateisystem zu bemühen, wären Webseiten, die Grafiken oder Bilder enthalten. In diesem Fall müssen die Bilddateien parallel zu den aufgerufenen HTML-Dateien im Verzeichnis liegen. Per write oder andere Methoden gibt es keine Möglichkeit, Bildobjekte in eine Seite zu bekommen.
Ausnahme sind hier Systeme mit installiertem Internet Explorer 9, dem man neuerdings über HTML5 oder SVG dynamisch Bilder über Skripte und das MSHTML-Modell zuweisen kann. Aber das wäre Thema für einen weiteren Beitrag.
Web-Inhalte schreiben
Das Vorgehen, um den HTML-Code über die write-Methode in die Browser-Seite zu schreiben, lässt sich anhand Listing 1 verdeutlichen, das in der Beispieldatenbank im Formular frmWeb zu finden ist.
Listing 1: Webinhalt dynamisch schreiben
Private Sub cmdScriptor_Click() Dim oDoc As Object Dim sHTML As String CWeb.Navigate2 "about:blank" WaitForReady Set oDoc = CWeb.Document sHTML = "<form><input type=""button"" value=""Knopf"" onClick=""javascript:alert(''Huhu!'');""></input></form>" oDoc.write sHTML oDoc.body.Style.background = CStr("#D0D0B0") oDoc.write "Seite mit Knopf" End Sub
Damit die write-Methode überhaupt angewandt werden kann, muss im Browser bereits ein Dokument geladen sein – schließlich ist write eine Methode des Document-Objekts.
Und das lässt sich am einfachsten erledigen, indem zunächst eine leere Seite mit about:blank erzeugt wird.
In der Prozedur sehen Sie, dass eine Hilfsvariable CWeb eingesetzt wird, die in der Prozedur nicht deklariert ist. Diese enthält einen Verweis auf das Webbrowser-Steuerelement und ist im Kopf des Moduls so deklariert, dass sie Ereignisse auslösen kann:
Private WithEvents CWeb As SHDocVw.WebBrowser
Die Zuweisung geschieht im Load-Ereignis des Formulars:
Set CWeb = Me!ctlWeb.Object
In weiteren Prozeduren des Formulars kann fortan diese Objektvariable verwendet werden, statt der länglichen Form mit dem Verweis auf das Steuerelement.
Nachdem der Browser angewiesen wurde, ein leeres Dokument zu erzeugen, kann auf dieses in VBA noch nicht unmittelbar zugegriffen werden. Der Browser braucht dafür einige Zeit, die asynchron zum VBA-Code abläuft.
Aus diesem Grund gibt es den Aufruf einer Warteschleife, die in die zusätzliche Prozedur WaitForReady ausgelagert ist:
Private Sub WaitForReady() Do DoEvents Loop Until CWeb.ReadyState >= READYSTATE_INTERACTIVE End Sub
Der Browser gibt anhand eines Flags der Eigenschaft ReadyState kund, wie es um den Zustand des Dokuments bestellt ist. Ist dieser Wert größer oder gleich 3, was der Konstanten READYSTATE_INTERACTIVE entspricht, dann steht das Dokument für den Zugriff bereit.
Das geladene Dokument wird im weiteren Verlauf der Objektvariablen oDoc zugewiesen, die im Prozedurkopf As Object deklariert ist. An sich könnte man dafür auch gleich den korrekten Typ HTMLDocument verwenden. Doch in diesem Fall streikt VBA beim Aufruf der write-Methode wegen inkompatibler Variant-Datentypen.
Im String sHTML wird der Inhalt der Seite zusammengestellt. Dabei muss man sich vergegenwärtigen, dass das leere Dokument bereits durchaus HTML-Code enthält – nämlich die Elemente HTML und BODY. Die write-Methode schreibt also innerhalb der body-Tags.
Wie am Listing zu erkennen ist, können dabei auch mehrere write-Anweisungen hintereinander folgen. Der Code wird dann sequenziell in die Seite geschrieben.
Um zu demonstrieren, dass die Seite auch anders als durch HTML-Code zu beeinflussen ist, wird ihre Hintergrundfarbe über das DOM-Modell manipuliert, was über die style-Eigenschaft background des body-Elements geschieht.
Nach dem Auslösen der Prozedur über die Schaltfläche (s. Bild 2) ändert sich das Browser-Fenster und zeigt die rudimentäre Webseite an.
Bild 2: Das per VBA generierte Webformular im Browser-Steuerelement
Der HTML-Code der Variablen sHTML im Listing besteht aus einem HTML-Formular mit einem input-Element, also einer Schaltfläche, die direkt eine Zeile Javascript ausführt, nämlich die Anzeige eines Meldungsfensters.
Es lässt sich festhalten, dass dem Webbrowser-Steuerelement Web-Inhalte unmittelbar per VBA zugewiesen und dabei auch Javascript-Abschnitte integriert werden können.
Javascript-Funktionen per VBA aufrufen
Üblicherweise werden Javascript-Funktionen in Webseiten dazu verwendet, um auf Aktionen zu reagieren, welche von Ereignissen hervorgerufen werden. In der Regel handelt es sich dabei um Elemente innerhalb eines form-Tags, wie eben der input-Button in Bild 2.
Andere Ereignisquellen könnten das Laden der Seite selbst sein, Maus-Klick-Events auf bestimmte Elemente oder Zeitgeber, die in Intervallen Aufgaben erledigen sollen.
Geht der Umfang des Scripts über eine Zeile hinaus, dann werden solche Funktionen im Interesse besserer Strukturierung separat in den Quelltext geschrieben, anstatt, wie im Beispiel, das Skript direkt in das Element-Tag einzubinden. Der Quelltext hätte alternativ so wie in Listing 2 ausgesehen.
Listing 2: Einfache Webseite mit Javascript-Funktion
<script type="text/javascript"> function fuScript() { alert(''Huhuu!''); } </script> <form> <input type="button" value="Knopf" onClick="fuScript()"/> </form>
Hier wird im input-Element angegeben, dass auf Klick die Skript-Funktion fuScript aufgerufen werden soll.
Interessant wäre nun, wenn sich solche Funktionen, die ja auch weit umfangreicher programmiert sein können, nicht nur durch Ereignisse der Webseitenelemente ausführen ließen, sondern auch direkt aus VBA heraus.