Tagmodell des Webbrowsers
von Thomas Mell
Übersicht
Wer über Erfahrungen mit HTML und Javascript (oder Jscript, VBScript) verfügt, wird feststellen, daß das Ansprechen von HTML-Objekten mit VB fast identisch ist. Oder anders herum, wer es in VB beherrscht wird auch keine Probleme mit Javascript haben.
Um die hier genannten Möglichkeiten nutzen zu können, müssen Sie die Komponente "Microsoft HTML Object Library" (mshtml.dll) zu Ihren Projekt hinzufügen. Weiterhin sollte man über gute Kenntnisse in HTML verfügen.
Mit freundlichen Grüßen
Thomas Mell TMell@T-Online.de
Unterschiede zwischen IE4 und IE5 [oder höher]
Im IE4 kann man nur mittels des all-Objekts auf HTML-Objekte zugreifen. Da es sich bei diesem Objekt um eine microsofteigene Erfindung handelt, das W3-Konsortium hatte seinerzeit noch keine Spezifikationen für den Zugriff auf HTML-Objekte bereitgestellt, sollte es auch nur in Umgebungen benutzt werden, in denen der IE4 installiert ist.
Da mittlerweile die oben genannten Spezifikationen existieren, wurde ab der Version 5 das all-Objekt durch eine Sammlung von Methoden abgelöst. Damit diese Versionen abwärtskompatibel zum IE4 bleiben, existiert das all-Objekt in diesen weiter, sollte aber nicht mehr benutzt werden. Die neuen Methoden sind jedoch kein Bestandteil dieses, sondern werden in einem weiterführenden Artikel behandelt. Für Programme die verteilt werden, sollte man unbedingt mit dem all-Objekt arbeiten, da man nie sicher sein kann, daß bei jeden User der IE5 oder höher installiert ist.
In Umgebungen, die ab IE5 bereitsteht (z.B. Intranets) sollte man dagegen mit den "neuen" Methoden arbeiten, da diese bedeutend mächtiger und leichter zu handhaben sind.
Zugriff auf Formulare
Sehr häufig wird der Wunsch geäußert auf Formulare und deren Elemente (Textfelder, Radiobuttons, Checkboxen, Popup-Menüs...) zuzugreifen, bzw. diese auszulesen oder zu füllen/setzen. Aus diesem Grund existieren im IE (egal welche Version) 3 Objekte, die nur für die Behandlung von Formularen bereitstehen - Forms , Elements und Options . Natürlich kann man auch mit dem (weiter unten erklärten) all-Objekt und der DOM-Syntax auf Formulare und deren Elemente zugreifen, das wäre aber mit Kanonen auf Spatzen geschossen.
Eine umfangreiche Erklärung dieser Objekte und deren Methoden/Eigenschaften würde den Rahmen dieses Artikel sprengen (dazu wird es einen eigenen Artikel geben). Ich werde jedoch die am häufigsten vorkommenden Anwendungen darstellen.
Als erstes wird beschrieben wie auf ein Formular zugegriffen wird (nicht auf die darin enthalten Elemente, dazu kommen wir später). Formulare liegen im IE als Objekte vor, und zwar vom Typ Forms .
Dieses Objekt besitzt u.a. die Eigenschaften:
Eigenschaft | Beschreibung |
---|---|
action | Die URL, zu welcher das Formular geschickt werden soll. |
name | Der Name des Formular, welcher im Name-Attribut steht. |
target | Gibt den Namen des Frame an, in welchem eine Antwortseite des Server angezeigt werden soll. |
length | Anzahl der Formulare im Dokument. |
Tabelle 1
Da ein HTML-Dokument mehrere Formulare enthalten kann, könnte man zunächst feststellen um wieviele es sich dabei handelt, folgendes erledigt dies für uns:
WebBrowser1.Document.Forms.length
Da gleichnamige Tags [hier das <Form> Tag] als Objektarray [ich nenne es einfach mal so] vorliegen, kann man diese auch wie ein Array ansprechen:
WebBrowser1.Document.Forms(1)
gibt uns das zweite <Form> Tag als Objekt zurück.
Sollte ein Formular über ein name-Attribut verfügen, kann dieses auch über:
WebBrowser1.Document.Forms("formularName")
als Objekt erhalten werden.
Nun steht nichts im Wege die Eigenschaften des form-Objekt auszulesen oder neu zu beschreiben:
x = WebBrowser1.Document.Forms("formularName").action
gibt die Absende-URL zurück. Möchten Sie diese ändern ?
WebBrowser1.Document.Forms(1).action = "neueURL"
Wo Objekte sind, da sind nicht nur Eigenschaften sondern auch Methoden (meistens). Da macht auch das forms -Objekt keine Ausnahme:
Methode | Beschreibung |
---|---|
reset | Löscht alle Formularinhalte. |
submit | Schickt das Formular ab. |
Tabelle 2
Ein Formular abzuschicken ist somit ein Kinderspiel:
WebBrowser1.Document.Forms("meinFormular").submit
In VB existieren für alle möglichen Tags eigene Objekttypen. Hier wäre dies HTMLFormElement
Dim myForm As HTMLFormElement Set myForm = WebBrowser1.Document.Forms(0) myForm.action = "neueURL"
In myForm befindet sich nun das erste Formular als Objekt und es können alle Methoden und Eigenschaften angewandt werden. Diese finden Sie im Objektkatalog.
Wie von VB gewohnt, existieren auch in HTML-Dokumenten Ereignisse (Events). Diese Events können ohne großen Aufwand an VB "weitergeleitet" werden. Um bei Formularen zu bleiben, werde ich zeigen wie man in VB ein Ereignis auslöst, wenn ein Formular z.B. mit einen Mausklick auf dem Submit-Button abgeschickt wird.
Option Explicit Dim WithEvents myForm As HTMLFormElement Private Sub Form_Load() WebBrowser1.Navigate2 "formular.html" End Sub Private Sub WebBrowser1_DocumentComplete _ (ByVal pDisp As Object, URL As Variant) Set myForm = WebBrowser1.Document.Forms("meinFormular") End Sub Private Function myForm_onsubmit() As Boolean MsgBox "Wer wagt es mein Formular abzuschicken ?" End Function
Führen Sie bitte dieses Beispiel einmal aus - fällt ihnen etwas auf ? Die Messagbox erscheint, Sie klicken auf "ok" und was passiert ? Nichts, rein gar nichts - das Formular wird nicht abgeschickt. Warum?
Das liegt darin begründet, daß beim Auslösen dieses Events dieses zwar ausgeführt wird, aber nicht die Aktion welches das Event verursacht hat [hier der Klick auf den Submit-Button]. Das Event erwartet nämlich einen Rückgabewert, ob die Aktion letztendlich ausgeführt werden soll oder nicht.
Aus diesem Grund werden bei HTML-Events häufig Funktionen benutzt [siehe oben - myForm_onsubmit]. Da wir keinen Rückgabewert angegeben haben, wird defaultmäßig "False" benutzt und das Formular nicht abgeschickt.
Fügen Sie nun bitte die Zeile:
myForm_onsubmit = True
unterhalb der MsgBox-Zeile ein und schon macht sich das Formular auf die Socken. Alle weiteren Events des Objektes finden Sie [wo sonst] im Objektkatalog.
Der IE stellt ein "richtiges" Event-Objekt zur Verfügung, worüber jede Aktion des User abgefangen werden kann [wie in VB, aber bedeutend mächtiger] Dieses Objekt werde ich in einen weiteren Artikel vorstellen.
Zugriff auf Formularelemente
Der Zugriff auf Formularelemente stellt sich genau so trivial dar wie der auf Formulare. Wie sollte es anders sein, für die Elemente existiert ein Objekt namens Elements . Wie im Forms -Objekt kann auch im Elements -Objekt ein Element über einen Index oder dessen Name [steht im Name-Attribut ] erreicht werden:
WebBrowser1.Document.Forms(0).elements(0) WebBrowser1.Document.Forms(0).elements("MyFormElement") WebBrowser1.Document.Forms("MyForm").elements(8) WebBrowser1.Document.Forms("MyForm").elements("MyFormElement")
Um was für ein Element handelt es sich aber bei dem entsprechenden Objekt ? Dafür gibt es die Eigenschaft Type :
WebBrowser1.Document.Forms(0).elements(0).Type
Mögliche Rückgabewerte:
Wert | Beschreibung |
---|---|
Text | Text-Eingabefeld |
Password | Passwortfeld |
Textarea | Mehrzeiliges Text-Eingabefeld |
Submit | Abschicken Button |
Reset | Reset Button |
Button | Button ohne Funktion [kann aber Events auslösen] |
Checkbox | Checkbox |
Radio | Radiobuttons |
Select-one | select-one |
select-multiple | select-multiple |
File | Upload - Element |
Hidden | Unsichtbares Feld [kann nur Text speichern] |
Tabelle 3
Jetzt müssen wir nur noch wissen wie die Werte der Elemente gelesen bzw. geändert werden können. Da dies je nach Elementetyp sehr verschieden realisiert wird, werden diese einzeln beschrieben.
- text, password, textarea, hidden
<input type="text, password, textarea, hidden" name="Name" value="Wert">
Diese Elemente können nur Text enthalten.
x = WebBrowser1.Document.Forms(0).elements(0).value WebBrowser1.Document.Forms(0).elements(0).value = "neuer Wert"
- checkbox, radiobutton
<input type="submit, reset, button" name="meinName" value="ButtonText">
Da es sich bei diesen Elementen um Buttons handelt, wird der Beschriftungstext gelesen / geändert. Die Syntax ist identisch mit dem obigen Punkt.
- text, password, textarea, hidden
<input type="checkbox" name="meinName" value="meinWert">
<input type="radio" name="meinName" value="meinWert-1"> <input type="radio" name="gleicherName" value="meinWert-2"> <input type="radio" name="gleicherName" value="meinWert-3">
Bei diesen Buttons gibt es nur zwei Zustände - True oder False
x = WebBrowser1.Document.Forms(0).elements(0).Checked
WebBrowser1.Document.Forms(0).elements(0).Checked = True
x = WebBrowser1.Document.Forms(0).elements(0).Value
- select-one
Dieses Element besteht nicht nur aus einem Tag, sondern aus mehreren. Deswegen unterscheidet es sich grundlegend von allen anderen Formularelementen. Eingeleitet wird es mit dem <select> Tag und jeder Auswahlpunkt besteht aus einem <option> Tag.
<select name="meinMenue"> <option value="FF0000">Rot</option> <option value="00FF00">Grün</option> <option value="0000FF">Blau</option> </select>
Im elements Objekt befindet sich aber nur das select-Tag als Objekt. Für die option-Tags existiert [wie wäre es auch anders zu erwarten] das options Objekt. Jetzt wird es etwas komplizierter, da mehrere Möglichkeiten existieren auf diesen Wulst von Objekten zuzugreifen. Fangen wir mal mit einem einfachen Beispiel an:
Mit
x = WebBrowser1.Document.Forms(0).elements(0).length
ermitteln wir die Anzahl der Auswahlmöglichkeiten und
x = WebBrowser1.Document.Forms(0).elements(0).selectedIndex
oder
x = WebBrowser1.Document.Forms(0).elements("Menue").selectedIndex
gibt den Index der aktiven Auswahl zurück.
Einen Menüpunkt selektieren können wir mit
WebBrowser1.Document.Forms(0).elements("Menue").selectedIndex = 2
Um auf die Eigenschaften eines Menüpunktes zuzugreifen, bringen wir nun das options Objekt ins Spiel. Achtung: Das options Objekt kann NUR mit einem Index belegt werden. Im Gegensatz zum forms und elements Objekt darf dort nicht der Name eines <option> Tag benutzt werden.
WebBrowser1.Document.Forms_ (0).elements("Menue").options(2).selected = True
bewirkt genau das Selbe wie im Beispiel zuvor.
x = WebBrowser1.Document.Forms(0).elements("Menue").options(1).value
Liefert uns den value-Wert und
x = WebBrowser1.Document.Forms(0).elements("Menue").options(1).Text
den sichtbaren Text des 2. Menüpunktes.
Wie Sie sehen, kann nur ermittelt werden, welcher Menüpunkt aktiv ist, bzw. den Wert eines bestimmten Menüpunktes. Um den Wert [oder Text] des aktiven Menüpunktes zu erfahren, muß man beide Möglichkeiten kombinieren:
WebBrowser1.Document.Forms(0).elements(0).Options _ (WebBrowser1.Document.Forms(0).elements(0).selectedIndex).Value
Und zu guter letzt erkläre ich noch wie Menüpunkte entfernt bzw. hinzugefügt werden. Hierfür müssen wir zwischen dem IE4 und IE5 oder höher unterscheiden.
Das Entfernen eines Menüpunktes
IE4
Beim IE4 existiert keine Möglichkeit Menüpunkte zu entfernen. Allerdings kann man mit der length Eigenschaft die Liste verkürzen:
WebBrowser1.Document.Forms(0).elements("Menue").length = 2
Waren zuvor z.B. 5 Menüpunkte vorhanden, dann würde nun nur noch die ersten 2 angezeigt werden.
IE5 oder höher
Im Gegensatz zum IE4 bereitet es im IE5 oder höher keinerlei Problem einzelne Menüpunkte zu entfernen:
WebBrowser1.Document.Forms(0).elements("Menue").removeChild _ (WebBrowser1.Document.Forms(0).elements("meinMenue").children(4))
oder etwas leserlicher:
Dim optio As HTMLOptionElement Set optio = WebBrowser1.Document.Forms(0).elements("meinMenue") optio.removeChild (optio.children(4))
Da diese Syntax zum DOM-Wortschatz gehört, möchte ich darauf nicht näher eingehen [auch dazu werde ich noch einen eigenen Artikel verfassen]. In diesem Beispiel brauchen Sie nur zu wissen das der Index des zu löschenden Menüpunktes in der Methode children angegeben wird [hier der 5. Eintrag].
Hinzufügen von Menüpunkten
IE4
Auch hier können wir neue Elemente nur am Ende der Liste anfügen:
Als erstes ermitteln wir die Anzahl der Einträge...
x = WebBrowser1.Document.Forms(0).elements(0).length
....dann erhöhen wir die Anzahl um eins....
WebBrowser1.Document.Forms(0).elements(0).length = x + 1
....und nun den Text angeben.....
WebBrowser1.Document.Forms(0).elements(0).Options(x).Text = "Neuer Eintrag"
....und zu guter letzt einen Wert verpassen.
WebBrowser1.Document.Forms(0).elements(0).Options(x).Value = "Neuer Wert"
IE5 oder höher
Wie nicht anders zu erwarten, kann im IE5 oder höher an jeder Stelle der Liste ein neuer Eintrag hinzugefügt werden:
Eine Objektvariable vom Typ IHTMLOptionElement anlegen.......
Dim optio As IHTMLOptionElement
.... dann ein neues OPTION-Objekt erzeugen...
Set optio = WebBrowser1.Document.createElement("OPTION")
....dem neuen Objekt einen "Text”.....
optio.Text = "Neuer Eintrag"
....und einen "Wert” geben...
optio.Value = "Neuer Wert"
....und zum Schluß ins Menü einfügen.
WebBrowser1.Document.Forms(0).elements("meinMenue").Add optio, 4
In der letzten Zeile wird die Position angegeben, an welcher der neue Eintrag eingefügt wird [4.]
select-multiple
Dieses Element ist weitgehend identisch mit dem select-one - PopMenü. Es unterscheidet sich lediglich durch die Möglichkeit mehrere Menüpunkte zu selektieren. Das Aktivieren eines Menüpunktes wird genau so realisiert wie beim select-one - PopMenü.
WebBrowser1.Document.Forms(0).elements(0).Options(2).Selected = True WebBrowser1.Document.Forms(0).elements(0).Options(4).Selected = True
Selektiert den 3. und 5. Menüpunkt.
Um festzustellen welche Menüpunkte aktiv sind, müssen wir alle in einer Schleife überprüfen:
Dim n For Each n In WebBrowser1.Document.Forms(0).elements(0).Options If n.Selected Then Debug.Print n.Value Next n
Dieses Beispiel schreibt alle Werte der aktiven Menüpunkte ins Debugfenster.
Das all-Objekt
Mit Hilfe des all-Objekts hat man Zugriff auf alle Tags und Inhalte einer HTML-Datei. Die meisten Attribute kann man lesen und ändern. Methoden des all-Objekts erlauben unter anderem das Einfügen oder Entfernen von HTML-Tags, Attributen und lesbaren Text. Auf diese Weise ist der dynamische Zugriff auf alle Bestandteile einer HTML-Datei möglich. Von "Hause" aus stellt das all-Objekt eine Liste aller Tags bereit, welche wie ein Array angesprochen werden können. Jedes Tag steht innerhalb dieser Liste als Objekt zur Verfügung auf welche wiederum eine Unmenge Methoden und Eigenschaften angewandt werden können.
WebBrowser1.Document.All(0).outerHTML
Hiermit greifen wir auf das erste (Index 0) Tag im Dokument zu, welches immer das <HTML> Tag darstellt. Mit der Methode outerHTML erhalten wir den gesamten Inhalt dieses Tags einschließlich sich selbst, also z.B.:
<html> <body> <p>Hallo Welt</p> </body> </html>
Somit erhalten wir den gesamten HTML-Quelltext des Dokumentes.
Dagegen erhält man mit der Methode innerHTML nur den Inhalt eines Tags. In unseren Fall also:
<code> <body> <p>Hallo Welt</p> </body> </code>
Weiterhin existiert noch die Methode innerText, womit man den lesbaren [gleich dem im Browser sichtbaren] Text erhält:
Hallo Welt
Und zu guter letzt kann man mit all.length die Anzahl aller Tags ermitteln:
3
Da man eigentlich nur beim <HTML> Tag den Index kennt [immer 0] ist das Ansprechen anderer Tags reine Glückssache, es sei denn es handelt sich um selbst geschriebene Dokumente und man macht sich die Mühe die Indexe der benötigten Tags abzuzählen. Aber zum Glück gibt es dafür noch weitere Methoden. Da wäre z.B. tagName:
Dim n For Each n In WebBrowser1.Document.All Debug.Print n.tagName Next n
Dies gibt alle Tagnamen aus.
HTML BODY P
So kann man zumindest schon mal nach bestimmten Tags suchen. Da es dabei doch recht mühselig ist z.B. nach dem x-ten <P> Tag zu suchen, können wir uns das Leben mit der Methode tags("TAG") erleichtern. Diese Methode stellt uns (wie das all-Objekt) eine Liste von Tags zur Verfügung, aber nur von einer "Sorte”:
WebBrowser1.Document.All.tags("A").length
Gibt uns die Anzahl aller <A> Tags zurück. Nun kann man wiederum mit
WebBrowser1.Document.All.tags("A")(5).innerText
Den Textinhalt des 6. <A> Tag auslesen.
Genau so einfach kann man auch auf die Attribute eines Tag zugreifen. Sie möchten die Hintergrundfarbe der Seite wissen ? Kein Problem:
WebBrowser1.Document.All.tags("BODY")(0).bgColor
Oder aber das Hintergrundbild ?
WebBrowser1.Document.All.tags("BODY")(0).background
Darf es die externallinkadresse des 9. <A> Tag sein ?
WebBrowser1.Document.All.tags("A")(8).href
Der Filename des 3. Bildes?
WebBrowser1.Document.All.tags("IMG")(2).src
Oder die Breite ?
WebBrowser1.Document.All.tags("IMG")(2).Width
Usw....
Das ist zwar alles schön und gut, aber wie soll man auf ein Bild zugreifen von dem man nicht den Index kennt ? Bei "fremden” Seiten hat man da keine Chance, sehrwohl aber bei eigenen. Dafür muß man in den Tags welche man ansprechen möchte das Attribut id schreiben:
<html> <body> <img id=”meinBild” src=”vollDasBild.gif”> </body> </html>
Nun ist es ein leichtes das <img> Tag ohne Angabe eines Index anzusprechen:
WebBrowser1.Document.All.meinBild.src
Selbstverständlich kann man auch hier die oben gezeigten Methoden und Eigenschaften anwenden. Es existieren bei weitem noch mehr Methoden und Eigenschaften als hier dargestellt. Weitere Informationen darüber bekommt man bei Microsoft unter den im Anhang genannten URL`s.
Wie füge ich nun ein DIV-Element ein ?
Dim TestDiv As IHTMLDivElement Set TestDiv = WebBrowser1.Document.createElement("DIV") With TestDiv .Id = "TESTID" .Style.display = "block" .Style.position = "absolute" .Style.Left = "0" .Style.Top = "0" .innerHTML="TEXT" End With WebBrowser1.Document.body.appendChild TestDiv
Zum Abschluß zeige ich noch wie man ermitteln kann, das wievielte Tag im Dokument ein mit tags() oder all.id selektiertes Tag ist. Dies geschieht mit der Eigenschaft sourceIndex
WebBrowser1.Document.All.tags("INPUT")(2).sourceIndex
oder
WebBrowser1.Document.All.meinBild.sourceIndex
Zugriff auf Frames
Ergänzung vom 24.11.2007 durch Philipp Burch:
Das WebBrowser-Steuerelement stellt bequeme Möglichkeiten bereit, auf die einzelnen Frames einer Website mit Framesets zuzugreifen. Die Anzahl vorhandener Frames kann mittels WebBrowser1.Document.frames.length ausgelesen werden. Ist diese Anzahl grösser als Null, ist für jeden Frame wiederum ein Document-Objekt vorhanden:
WebBrowser1.Document.frames(0).Document
Damit kann auch ganz einfach auf verschachtelte Frames zugegriffen werden, indem durch rekursive Aufrufe einer Funktion so tief gesucht wird, bis man ein Document-Objekt findet, welches keine weiteren Frames beinhaltet (Document.frames.length = 0).
Private Sub ReadFrames(Doc As HTMLDocument) If Doc.frames.length > 0 Then 'Weitere Frames vorhanden Dim i As Long For i = 0 To Doc.frames.length - 1 Call ReadFrames(Doc.frames(i).Document) Next i Else 'Keine weiteren Frames vorhanden '-> Inhalt kann verwendet werden Call MsgBox("Frame: " & Doc.Title, vbInformation, "Frame") End If End Sub
Beispielprojekt
Projekt als Download [5600 Bytes]
externallinks zum Thema
Formularelementetypen
- Text
- Hidden
- Buttons
- Submit und Reset
- Password
- File
- Image
- Checkbox
- RadioButton
- Pop-Menüs
Objekte
- Forms Objekte
- Elements Objekt
- All Objekt
Ihre Meinung
Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.