{"id":55000349,"date":"2017-04-01T00:00:00","date_gmt":"2017-04-01T00:00:00","guid":{"rendered":"http:\/\/access-basics.de\/349"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Der_Webbrowser_als_Bildanzeige","status":"publish","type":"post","link":"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html","title":{"rendered":"Der Webbrowser als Bildanzeige"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/1a6c214b72ca489c86ed5ce7d397c30c\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p class='introduction'>Die Handhabung von Bildern in Formularen war und ist ein Dauerbrennerthema in vielen Foren. Das genuine Bildsteuerelement von Access weist auch in der zeitweilig modernisierten Version etliche Beschr&auml;nkungen auf. Das Anlage-Steuerelement ist zwar pfiffig, aber dessen Programmierung f&auml;llt reichlich umst&auml;ndlich aus. Doch zu unserem Favoriten haben wir schon fr&uuml;her einmal ein alternatives Steuerelement auserkoren: das Webbrowser Control.<\/p>\n<h2>Beispieldatenbank<\/h2>\n<p>Die Beispiele dieses Artikels finden Sie in der Datenbank <b>1702_BildWeb.zip<\/b>.<\/p>\n<h2>Das Webbrowser Control als Universalcontainer<\/h2>\n<p>In der Ausgabe <b>04\/2016 <\/b>von <b>Access Basics<\/b>, <b>Elemente f&uuml;r die Bildanzeige<\/b>, verglichen wir die m&ouml;glichen Methoden, um Bilder in Formularen und Berichten zur Anzeige zu bringen. Neben dem <b>Bildsteuerelement<\/b>, dem <b>Anlage<\/b>-Steuerelement, einer zweckentfremdeten <b>Schaltfl&auml;che<\/b> und dem <b>MSForms Image Control<\/b> kam dort auch ein <b>Webbrowser-Steuerelement <\/b>zum Einsatz. Es stellte sich heraus, dass Letzteres sich sowohl qualitativ, wie auch von der Programmierung her, sehr gut f&uuml;r diesen Zweck eignet. <\/p>\n<p>Tats&auml;chlich ist das <b>Webbrowser Control <\/b>als Host f&uuml;r den <b>Internet Explorer<\/b> eine Universalwaffe! &Uuml;berall da, wo der Fundus von Access-Steuerelementen versagt, l&auml;sst sich &uuml;ber den Webbrowser fast alles realisieren. Schlie&szlig;lich gibt es ja inzwischen sehr komplexe Applikationen, die rein webbasiert arbeiten; und dorthin geht ohnehin der Trend. Lieb&auml;ugeln Sie also eh schon mit der Portierung Ihrer Datenbank zu einer Webl&ouml;sung, so ist der integrierte Webbrowser unter Access ein n&uuml;tzlicher Anfang, um sich mit Webprogrammierung vertraut zu machen.<\/p>\n<p>Der Vorteil des <b>Webbrowser Controls<\/b> ist, dass es den gewaltigen Umfang der <b>HTML-Bibliothek<\/b> von Windows offenlegt. &Uuml;ber diese k&ouml;nnen Webseiten programmatisch nicht nur &uuml;ber HTML gesteuert werden, sondern auch &uuml;ber Objekte und deren Eigenschaften, sowie Methoden. Praktisch jedes <b>HTML-Tag<\/b> (Element) hat ein Pendant als Objektklasse in der HTML-Bibliothek von Microsoft. &Uuml;ber weitere Hilfsbibliotheken, auf die Sie verweisen k&ouml;nnen, wie die <b>Microsoft XML Library<\/b> oder die <b>Shell<\/b>-Bibliothek, haben Sie schlie&szlig;lich den <b>Internet Explorer <\/b>vollst&auml;ndig im Griff.<\/p>\n<h2>Webbrowser vs. Anlagesteuerelement<\/h2>\n<p>Das Anlagesteuerelement scheint alle L&ouml;sungen zur Bildanzeige dadurch auszustechen, dass es die Bilddaten bin&auml;r aus einer Tabelle mit Anlagefeld hervorholen kann. Mit seinem Popup-Toolbar ist es zudem ohne jeglichen Programmcode m&ouml;glich, Bilddateien zu laden und direkt im gebundenen Feld zu speichern.  <\/p>\n<p>Ein Bild im Webbrowser hingegen verlangt nach einer <b>URL<\/b>, die den Pfad zur Datei enthalten muss. Ein Abspeichern der Bilddatei selbst in einem Tabellenfeld scheint damit verwehrt. Bestenfalls k&ouml;nnte man die Datei bin&auml;r in ein <b>OLE-Feld <\/b>laden, um dieses sp&auml;ter wieder als tempor&auml;re Datei zu exportieren und deren Pfad als <b>URL<\/b> dem Webbrowser Control zu &uuml;bergeben.<\/p>\n<p>Tats&auml;chlich jedoch gibt es eine L&ouml;sung, die diesen Umweg obsolet macht. Das Formular <b>frmBilder<\/b> der Beispieldatenbank zeigt, wie auf diese tempor&auml;re Datei &uuml;ber eine spezielle Kodierung der Bilddaten verzichtet werden kann. Damit steht diese L&ouml;sung dem Anlagesteuerelement in nichts nach. Sie erfordert lediglich einige &uuml;berschaubare VBA-Routinen.<\/p>\n<h2>Bildtabelle<\/h2>\n<p>Die Tabelle zur Speicherung sowohl des Bildpfads, wie auch der Bin&auml;rdaten, nennt sich <b>tblBilder<\/b> und zeigt sich in der Datenblattansicht wie in Bild 1. Das Feld <b>Datei<\/b> nimmt den vollen Pfad der Bilddatei auf. <b>BildName<\/b> dient zur optionalen Angabe einer Bezeichnung des Bilds und ist im Entwurf der Tabelle auf den Text <b>Bild<\/b> voreingestellt. Schlie&szlig;lich sollen die Bin&auml;rdaten des Bilds im Feld <b>Binaer<\/b> aufgenommen werden, das hier aber nicht, wie eher &uuml;blich, als <b>OLE-Feld<\/b> daherkommt, sondern als <b>Memo<\/b>-Feld.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/tblBilder1.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/tblBilder1.png\" alt=\"Die Tabelle tblBilder enth&auml;lt zun&auml;chst nur die Pfade zu den Bilddateien im Feld Datei und einen Default-Namen\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 1: Die Tabelle tblBilder enth&auml;lt zun&auml;chst nur die Pfade zu den Bilddateien im Feld Datei und einen Default-Namen<\/p>\n<p>Den Grund erfahren Sie sp&auml;ter. Der Entwurf der Tabelle ergibt sich damit gem&auml;&szlig; Bild 2. Der Autowert <b>ID<\/b> als Prim&auml;rschl&uuml;ssel vervollst&auml;ndigt die Tabelle. <\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/tblBilder_Design.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/tblBilder_Design.png\" alt=\"Entwurfsansicht der Tabelle tblBilder\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 2: Entwurfsansicht der Tabelle tblBilder<\/p>\n<p>Die angezeigten Datens&auml;tze kommen &uuml;brigens beim Aufruf des <b>Intro<\/b>-Formulars zustande. Hier ist eine kleine Routine <b>UpdatePics<\/b> hinterlegt, die alle Bilddateien, die sich im Datenbankpfad befinden, enumeriert und in der Tabelle ablegt. Bei Ihnen wird der Inhalt der Tabelle deshalb wohl anders aussehen.<\/p>\n<p>Die Tabelle stellt die Basis f&uuml;r das Formular <b>frmBilder<\/b> dar, wobei dort das Webbrowser-Steuerelement an das Feld <b>Datei<\/b> gebunden ist. Damit zeigt es die Bilder auch schon ordnungsgem&auml;&szlig; an, falls die Pfadangaben stimmen. Gleichzeitig kodiert eine Prozedur die Bilddaten und speichert sie im Feld <b>Binaer<\/b> (siehe Bild 3). Bei erneutem Aufruf des Datensatzes im Formular schaut der Code im Ereignis <b>Beim Anzeigen<\/b> (<b>Form_Current<\/b>) nach, ob das Feld <b>Binaer<\/b> leer ist. Da das nun nicht mehr der Fall ist, verwendet es die Daten des Memo-Felds zur Bildanzeige, ohne eine Datei lesen zu m&uuml;ssen. Soweit der &Uuml;berblick! Schauen wir uns das im folgend im Detail an&#8230;<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/tblBilder2.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/tblBilder2.png\" alt=\"Das Memo-Feld Binaer f&uuml;llt sich sp&auml;ter beim Aufruf eines Bilds im Webbrowser des Formulars frmBilder\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 3: Das Memo-Feld Binaer f&uuml;llt sich sp&auml;ter beim Aufruf eines Bilds im Webbrowser des Formulars frmBilder<\/p>\n<h2>Bild im Webbrowser im Formular<\/h2>\n<p>Der Entwurf des Formulars <b>frmBilder<\/b> (siehe Bild 4) ist so schlicht, wie die zugrundeliegende Tabelle. Die Textfelder oben im Formularkopf sind an die entsprechenden Tabellenfelder <b>BildName<\/b> f&uuml;r die Bezeichnung und <b>Datei<\/b> f&uuml;r den Pfad zur Bilddatei gebunden. &Uuml;ber den blauen Button <b>cmdLoad<\/b> kann ein Dateiauswahldialog ge&ouml;ffnet werden, um ein Bild aus dem Dateisystem laden zu k&ouml;nnen. Das rote Label mit der Beschriftung <b>Bin&auml;r<\/b> ist auf Unsichtbar gestellt und wird erst per Code zum Vorschein gebracht.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/frmBilder_Design.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/frmBilder_Design.png\" alt=\"Das Webbrowser-Control in der Mitte des Formularentwurf von frmBilder\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 4: Das Webbrowser-Control in der Mitte des Formularentwurf von frmBilder<\/p>\n<p>Im Detailbereich des Formulars befindet sich in voller Ausdehnung nur das Webbrowser-Steuerelement <b>ctlWeb<\/b>. Seine Verankerung ist auf <b>Quer und nach unten dehnen<\/b> eingestellt, damit es alle Gr&ouml;&szlig;en&auml;nderungen des ver&auml;nderbaren Formularrahmens mitmacht. Links oben steht in ihm auch schon der Steuerelementinhalt, der jedoch nicht den Namen des Tabellenfelds anzeigt, sondern den Ausdruck <b>=&#8220;about:blank&#8220;<\/b>.<\/p>\n<p>Tats&auml;chlich ist das Control nicht wirklich an die Tabelle gebunden, sondern nur indirekt &uuml;ber den VBA-Code des Formulars. Denn das Webbrowser-Steuerelement von Access <b>muss<\/b> nicht zwingend an ein Feld gebunden sein. Sie k&ouml;nnen auch eine feste <b>URL<\/b> im Eigenschaftenblatt unter <b>Steuerelementinhalt<\/b> eintragen, die dann standardm&auml;&szlig;ig angezeigt wird. Mit dem vorliegenden Eintrag erhalten Sie immer eine leere Seite.<\/p>\n<p>Im Fu&szlig;bereich des Formulars gibt es einige zus&auml;tzliche Elemente, die Einfluss auf die Anzeige des Bilds haben. Ist das Kontrollk&auml;stchen <b>Originalgr&ouml;&szlig;e<\/b> aktiviert, so wird das Bild in seiner vollen Ausdehnung gerendert. Andernfalls passt es sich, je nach Breite oder H&ouml;he, genau in die Fl&auml;che des Webbrowser Controls ein. Die f&uuml;nf Schaltfl&auml;chen daneben demonstrieren, dass sich &uuml;ber das <b>HTML-Objektmodell<\/b> auch auf sehr einfache Weise Bildeffekte erzielen lassen. Hier k&ouml;nnen Sie das Bild horizontal oder vertikal spiegeln, sowie im oder gegen den Uhrzeigersinn um 90&deg; drehen.<\/p>\n<p>Der <b>Undo<\/b>-Button macht solche &Auml;nderungen r&uuml;ckg&auml;ngig. In Bild 5 sehen Sie ein geladenes Beispielbild. Hier  hat das Control das Bild aus dem Dateipfad eingelesen. Im Hintergrund aber wurden dessen Daten, wie erw&auml;hnt, in die Tabelle geschrieben.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/frmBilder_nobinary.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/frmBilder_nobinary.png\" alt=\"So pr&auml;sentiert sich das Formular frmBilder dann zur Laufzeit\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 5: So pr&auml;sentiert sich das Formular frmBilder dann zur Laufzeit<\/p>\n<p>So kommt es bei erneutem Aufruf des Datensatzes zur Darstellung in Bild 6: Das <b>Bin&auml;r<\/b>-Label oben wird eingeblendet und zus&auml;tzlich gibt rechts unten ein weiteres Label Auskunft &uuml;ber den Speicherbedarf des Bilds im Memo-Feld der Tabelle. Da es sich im Beispiel um ein Bitmap-Format handelt, im Textfeld <b>Bilddatei<\/b> zu erkennen, ist dieser ziemlich hoch.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/blumenkohl_small.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/blumenkohl_small.png\" alt=\"Ist ein Bild bereits eingelesen, so zeigt sich das Label Bin&auml;r oben rechts\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 6: Ist ein Bild bereits eingelesen, so zeigt sich das Label Bin&auml;r oben rechts<\/p>\n<p>Bei Linksklick auf das Bild erscheint eine Meldung, die direkt die aktuell im Webbrowser Control hinterlegte <b>URL<\/b> ausgibt. Bei aus dem Dateisystem geladenem Bild ergibt sich dabei etwa die Meldung in Bild 7. Hier hat der <b>Internet Explorer<\/b> den Pfad in das <b>file<\/b>-Protokoll umgewandelt und die <b>Backslashes<\/b> automatisch in <b>Slashes <\/b>umgewandelt.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/clickmsg1.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/clickmsg1.png\" alt=\"Info-Meldung beim Klick auf das Bild\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 7: Info-Meldung beim Klick auf das Bild<\/p>\n<p>Kommt das Bild hingegen bin&auml;r aus der Tabelle, so zeigt die Meldung, wie in Bild 8, deren Memo-Text ausschnittsweise an. Daf&uuml;r kommt keineswegs anderer Code zum Einsatz. Tats&auml;chlich handelt es sich bei dem langen String unmittelbar um die <b>Source-URL<\/b> des Browsers!<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/clickmsg2.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/clickmsg2.png\" alt=\"Info-Meldung bei bin&auml;rem Inhalt des Bilds\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 8: Info-Meldung bei bin&auml;rem Inhalt des Bilds<\/p>\n<p>Bei Rechtsklick auf das Bild erscheint ein Kontextmen&uuml;, wie sonst im <b>Internet Explorer<\/b> auch (siehe Bild 9). Leider hat man auf dessen Eintr&auml;ge ohne gr&ouml;&szlig;ere Umst&auml;nde keinen Einfluss. Man kann es allerdings mit wenig Code auch deaktivieren, wie wir noch sehen werden. Wir haben dies zun&auml;chst nicht getan, weil damit deutlich wird, welche M&ouml;glichkeiten das Webbrowser Control zur Verf&uuml;gung stellt. So etwa l&auml;sst sich das Bild, egal, ob als Datei oder bin&auml;r geladen, als Datei abspeichern, &uuml;ber den E-Mail-Client versenden oder ausdrucken.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/ie_context.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/ie_context.png\" alt=\"Das Kontextmen&uuml; des Webbrowser-Bilds\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 9: Das Kontextmen&uuml; des Webbrowser-Bilds<\/p>\n<p>Beim Speichern hat man die Wahl zwischen mehreren Dateiformaten, wie Bild 10 zeigt. Dabei scheint es keine Rolle zu spielen, welches Ursprungsformat das Bild hat. Auch bei <b>JPG<\/b> werden beim Abspeichern nur <b>PNG<\/b> und <b>BMP<\/b> angeboten.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/ie_saveas.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/ie_saveas.png\" alt=\"Beim Export des Bilds in eine Datei stellt der Webbrowser diese zwei Dateiformate zur Verf&uuml;gung\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 10: Beim Export des Bilds in eine Datei stellt der Webbrowser diese zwei Dateiformate zur Verf&uuml;gung<\/p>\n<p>Auch ein Kopieren des Bilds in die Zwischenablage ist m&ouml;glich, so dass es danach etwa in <b>Word<\/b> wieder eingef&uuml;gt werden kann. Allerdings kopiert das Control gleich mehrere Formate in die Zwischenablage, wie etwa neben dem Bitmap auch den Quelltext des Browsers. Beim Einf&uuml;gen in Word etwa m&uuml;ssen Sie die Funktion <b>Einf&uuml;gen | Inhalte einf&uuml;gen&#8230;<\/b> im <b>Start<\/b>-Tab des Ribbon bem&uuml;hen, was den Dialog in Bild 11 auf den Plan ruft. Hier ist <b>HTML<\/b> voreingestellt. Sie m&uuml;ssen stattdessen den Eintrag <b>Ger&auml;teunabh&auml;ngige Bitmap<\/b> ausw&auml;hlen, um das Bild in ein Dokument zu bekommen.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/Clipboard_Word.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/Clipboard_Word.png\" alt=\"Einf&uuml;gen des kopierten Bilds in MS Word\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 11: Einf&uuml;gen des kopierten Bilds in MS Word<\/p>\n<p>Am St&ouml;rendsten sind im Kontextmen&uuml; sicherlich die Eintr&auml;ge weiter unten, die einen Anwender, der gar nicht wei&szlig;, dass er einen Browser f&uuml;r die Bildanzeige vor sich hat, verwirren. Deshalb w&auml;re ein Abschalten des Kontextmen&uuml;s ratsam. Denn alle darin enthaltenen Anweisungen lassen sich gegebenenfalls auch recht einfach per Code &uuml;ber das Objektmodell des Browsers ausl&ouml;sen. Mit einigen Klimmz&uuml;gen lie&szlig;e sich das Kontextmen&uuml; sogar durch ein eigenes in der Datenbank angelegtes ersetzen. Da Microsoft leider seit mehreren Versionen keinen Editor f&uuml;r solche Men&uuml;s mehr in Access einbaut und deren Anlage deshalb rein programmtechnisch erfolgen muss, lassen wir diese M&ouml;glichkeit hier au&szlig;en vor.<\/p>\n<h2>Programmierung der Bildanzeige<\/h2>\n<p>Gehen wir Schritt f&uuml;r Schritt vor. Schalten Sie im Formular auf einen neuen Datensatz. Die Bildfl&auml;che bleibt wei&szlig;. &Uuml;ber den Button f&uuml;r den Dateiauswahldialog (<b>cmdLoad<\/b>) &ouml;ffnen Sie eine Bilddatei. Der dem <b>Click<\/b>-Ereignis hinterlegte Code steht in Listing 1 und verwendet das <b>FileDialog<\/b>-Objekt von Access oder, genauer, der Office-Bibliothek.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdLoad_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>ODlg<span style=\"color:blue;\"> As <\/span>Office.FileDialog\r\n     <span style=\"color:blue;\">Dim <\/span>sFile<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>sExt<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> ODlg = Application.FileDialog(msoFileDialogFilePicker)\r\n     <span style=\"color:blue;\">With<\/span> ODlg\r\n         .AllowMultiSelect = <span style=\"color:blue;\">False<\/span>\r\n         .InitialView = msoFileDialogViewDetails\r\n         .InitialFileName = CurrentProject.Path\r\n         .Filters.Add \"Bild-Dateien\", \"*.jpg,*.jpeg,*.png,*.bmp,*.tif*\"\r\n         <span style=\"color:blue;\">If <\/span>.Show<span style=\"color:blue;\"> Then<\/span>\r\n             sFile = .SelectedItems(1)\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(sFile) = 0<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n     \r\n     Me!txtDatei = sFile\r\n     sExt = <span style=\"color:blue;\">Mid<\/span>(sFile, <span style=\"color:blue;\">InStrRev<\/span>(sFile, \".\") + 1)\r\n     ...\r\n     ... (Fortsetzung folgt) ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p class='imagetext'>Listing 1: Beim Laden einer Bilddatei &uuml;ber den Button cmdLoad spielt sich diese Prozedur ab (erster Teil)<\/p>\n<p>Hier wird zun&auml;chst die Objektvariable <b>ODlg<\/b> auf das von Access zur Verf&uuml;gung gestellte <b>FileDialog<\/b>-Objekt gesetzt, wobei gleich der Dateiauswahlmodus &uuml;ber die Konstante <b>msoFileDialogPicker<\/b> angefordert wird. Im folgenden <b>With<\/b>-Block werden nun einige Einstellungen f&uuml;r den Dialog vorgenommen. Mehrfachauswahl etwa ist untersagt (<b>AllowMultiSelect<\/b>), die Ansicht wird auf Details gesetzt (<b>InitialView<\/b>), der Baum navigiert zum Datenbankverzeichnis (<b>InitialFileName<\/b>) und die erlaubten Dateiendungen sind auf einige Bildformate beschr&auml;nkt, mit denen der Internet Explorer klarkommt (<b>Filters<\/b>). Die Methode <b>Show<\/b> zeigt dann den Dialog erst an. Da der Dialog modal ist, h&auml;lt der Code an dieser Stelle an. Hat der Anwender eine Datei ausgew&auml;hlt, so quittiert die Funktion dies mit der R&uuml;ckgabe <b>True<\/b>, wonach die Variable <b>sFile<\/b> mit dem ersten und einzigen Element der <b>SelectedItems<\/b>-Auflistung best&uuml;ckt wird. Andernfalls ist die L&auml;nge des Strings in <b>sFile<\/b> gleich 0 und die Prozedur wird verlassen.<\/p>\n<p>Weiter wird nun der Dateipfad in das Textfeld <b>txtDatei<\/b> des Formulars geschrieben. Die  Dateiendung wird &uuml;ber einen Ausdruck mithilfe der <b>Mid<\/b>&#8211; und <b>InstrRev<\/b>-Funktionen ermittelt und in die Variable <b>sExt<\/b> gespeichert. Soweit die Vorarbeiten. F&uuml;r das Verst&auml;ndnis der restlichen Zeilen der Routine, die im Listing ausgelassen wurden, m&uuml;ssen erst die Vorg&auml;nge beim Laden und Anzeigen des Formulars n&auml;her beleuchtet werden.<\/p>\n<h2>Initialisierung des Webbrowser Controls beim Laden des Formulars<\/h2>\n<p>In Form_Load steht nur eine Zeile:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oBrowser = Me!ctlWeb.Object<\/pre>\n<p>Das Webbrowser-Steuerelement hat im Formular den Namen <b>ctlWeb<\/b>. Seine <b>Object<\/b>-Eigenschaft gibt den eigentlichen Webbrowser zur&uuml;ck, die der Objektvariablen zugewiesen wird. Deren Deklaration befindet sich im Modulkopf des Formulars:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oBrowser<span style=\"color:blue;\"> As <\/span>WebBrowser<\/pre>\n<p>Die Variable ist also vom Typ <b>Webbrowser<\/b> und das Statement <b>WithEvents<\/b> gibt an, dass dieses Objekt Ereignisse ausl&ouml;sen kann. Nun werden Sie eine Klasse <b>Webbrowser<\/b> im Objektkatalog vergeblich suchen. Die Access-Bibliothek enth&auml;lt deren Definition nicht. Der Typ ist n&auml;mlich in einer Bibliothek zu finden, die Sie erst einmal in die Verweise des VBA-Projekts laden m&uuml;ssen: die <b>Microsoft Internet Controls<\/b> (<b>shdocvw<\/b>). Diese Bibliothek ist das Kernst&uuml;ck des <b>Internet Explorers<\/b>. Markieren Sie nun im Objektkatalog die Klasse <b>Webbrowser<\/b>, so stellen Sie fest, dass diese fast die gleichen Methoden und Eigenschaften aufweist, wie die Klasse <b>WebbrowserControl<\/b> von Access, nur dass jene viele zus&auml;tzliche Eigenschaften zeigt, die sich auf die Gestalt des Steuerelements im Formulars beziehen. Microsoft hat im <b>WebbrowserControl<\/b> die Eigenschaften von Access-Steuerelementen mit denen des Internet Explorers vermengt.<\/p>\n<p>Nach dem Laden des Formulars navigiert das Steuerelement nun zur <b>URL<\/b> <b>about:blank<\/b>, wie das in seiner Eigenschaft <b>Steuerelementinhalt<\/b> festgelegt wurde. Also wird eine leere Seite in ihm angezeigt. Das Rendern dieser Seite ben&ouml;tigt dennoch etwas Zeit, weshalb im Ereignis <b>Beim Anzeigen<\/b> des Formulars (<b>Form_Current<\/b>) &uuml;ber die Funktion <b>WebDocReady<\/b> erst die Beendigung des Vorgangs abgewartet wird (siehe Listing 2).<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>WebDocReady(oBrowser<span style=\"color:blue;\"> As <\/span>WebBrowser)\r\n     Do\r\n         DoEvents\r\n     <span style=\"color:blue;\">Loop<\/span> Until oBrowser.ReadyState > READYSTATE_LOADED\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p class='imagetext'>Listing 2: Hilfsroutine zum Warten auf den Ladezustand eines Dokuments im Webbrowser Control<\/p>\n<p>Der Routine wird das Webbrowser-Objekt <b>oBrowser<\/b> als Parameter &uuml;bergeben. Eine Schleife, die lediglich die Anweisung <b>DoEvents<\/b> enth&auml;lt, wird solange wiederholt, bis der Ladezustand (<b>ReadyState<\/b>) des Browsers mindestens den Modus <b>LOADED<\/b> erreicht hat. Dann n&auml;mlich erst k&ouml;nnen die Objekteigenschaften des geladenen Dokuments angesprochen werden. Diese Schleife ist in eine externe Routine ausgelagert, weil sie unter Umst&auml;nden &ouml;fters im VBA-Projekt der Datenbank angesprochen wird. <\/p>\n<p>Listing 3 demonstriert den Code im Ereignis <b>Beim Anzeigen<\/b> (<b>Form_Current<\/b>) des Formulars. Das nun geladene Dokument wird einer Objektvariablen <b>oDoc<\/b> zugewiesen, die ebenfalls im Kopf des Moduls deklariert ist:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     WebDocReady oBrowser\r\n     <span style=\"color:blue;\">Set<\/span> oDoc = oBrowser.Document\r\n     \r\n     oDoc.body.innerHTML = \"<img id='bild' alt='fehlt!'\" &#038; _\r\n         \"label='Ein Bild' text-align: left><\/img>\"\r\n     DoEvents\r\n     <span style=\"color:blue;\">Set<\/span> oPic = oDoc.getElementById(\"bild\")\r\n     \r\n     <span style=\"color:blue;\">If <\/span>Me.NewRecord<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!Binaer)<span style=\"color:blue;\"> Then<\/span>\r\n         oPic.src = Me!Binaer.Value\r\n         Me!LblBinaer.Visible = <span style=\"color:blue;\">True<\/span>\r\n         Me!LblInfo.Visible = <span style=\"color:blue;\">True<\/span>\r\n         Me!LblInfo.Caption = Format(<span style=\"color:blue;\">Len<\/span>(Me!Binaer.Value), _\r\n             \"###,###,###\" & \" Bytes\")\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!Datei)<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Dir(Me!Datei.Value)) > 0<span style=\"color:blue;\"> Then<\/span>\r\n                 oPic.src = Me!Datei.Value\r\n                 LblBinaer.Visible = <span style=\"color:blue;\">False<\/span>\r\n                 Me!LblInfo.Visible = <span style=\"color:blue;\">False<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Do\r\n         DoEvents\r\n     <span style=\"color:blue;\">Loop<\/span> Until oPic.ReadyState = \"complete\"\r\n     wPic = oPic.Width: hPic = oPic.Height\r\n     chkScale_AfterUpdate\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p class='imagetext'>Listing 3: Vorg&auml;nge im Ereignis Beim Anzeigen des Formularmoduls<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oDoc<span style=\"color:blue;\"> As <\/span>HTMLDocument<\/pre>\n<p>Auch hier kommt die Anweisung <b>WithEvents<\/b> ins Spiel, denn nicht nur der Browser kann Ereignisse ausl&ouml;sen, sondern auch das Dokument selbst! W&auml;hlen Sie aus der linken oberen Combo des Code-Editors den Eintrag <b>oDoc<\/b> aus und w&auml;hlen Sie aus der rechten ein beliebiges Ereignis aus. Sofort legt VBA eine passende Ereignisprozedur an. So etwa auch f&uuml;r das Ereignis <b>oncontextmenu<\/b>, die ausgel&ouml;st wird, sobald im Dokument die rechte Maustaste bedient wird:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oDoc_oncontextmenu()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     oDoc_oncontextmenu = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Stellen Sie den R&uuml;ckgabewert der Ereignisfunktion auf <b>True<\/b> ein, so zeigt das Dokument das Kontextmen&uuml; des Internet Explorers an. Setzen Sie stattdessen <b>False<\/b> ein, so unterbleibt dies!<\/p>\n<p>Sie k&ouml;nnen den Wert auch in Abh&auml;ngigkeit eigener Berechnungen setzen. Das Kontextmen&uuml; soll in unserem Fall nur dann angezeigt werden, wenn die rechte Maustaste &uuml;ber dem Bild bet&auml;tigt wird, nicht aber im restlichen Bereich des Dokuments. Dazu ist diese Ereignisfunktion etwas auszubauen, worauf wir sp&auml;ter noch genauer eingehen. <\/p>\n<p>Die Objektvariable <b>oDoc<\/b> ist als Typ <b>HTMLDocument<\/b> deklariert. Auch f&uuml;r diese Typklasse ben&ouml;tigen Sie einen zus&auml;tzlichen Verweis in der Datenbank, n&auml;mlich die <b>Microsoft HTML Object Library<\/b> (<b>MSHTML<\/b>).<\/p>\n<p>Dieses gewaltige Objektmodell enth&auml;lt alles, was der Umgang mit einem Web-Dokument oder seinen Elementen erfordern kann. Sie ist deshalb auch die gr&ouml;&szlig;te Bibliothek, die Sie &uuml;berhaupt unter Windows finden werden. Zum Gl&uuml;ck ben&ouml;tigen wir nur einen winzigen Teil aus ihr.<\/p>\n<p>Die dritte Zeile in <b>Listing 3<\/b> zeigt gleich, wie auf das Objektmodell Bezug genommen wird. Das Dokument hat einen <b>Body<\/b>, der aus der Eigenschaft <b>body<\/b> von <b>oDoc<\/b> hervorgeht. Das <b>Body<\/b>-Objekt wiederum kennt zahllose Eigenschaften, von denen <b>innerHTML<\/b> eine ist. Sie bezieht sich auf den HTML-Code, der innerhalb der <b>body-Tags<\/b> steht. Und der kann hier ganz einfach modifiziert werden, was der Browser auch sofort in eine &Auml;nderung der Anzeige umsetzt, was sicherheitshalber noch mit einem eingeschobenen <b>DoEvents<\/b> vervollst&auml;ndigt wird, da dieser Vorgang ebenfalls etwas Zeit ben&ouml;tigt.<\/p>\n<p>Zum besseren Verst&auml;ndnis: Das Navigieren zu <b>about:blank<\/b> hat diesen Dokument-Code zur Folge:<\/p>\n<pre><HTML><BODY><\/BODY><\/HTML><\/pre>\n<p>Und zwischen diese <b>Body<\/b>-Tags wird nun der Code f&uuml;r ein Bild eingef&uuml;gt:<\/p>\n<pre><img id='bild' alt='fehlt!' label='Ein Bild'><\/img><\/pre>\n<p>Das Bild hat die Element-<b>ID<\/b> <b>bild<\/b> und die Beschriftung ist auf <b>Ein Bild<\/b> festgelegt. &Uuml;ber die <b>ID<\/b> kann sp&auml;ter auf einfache Weise Bezug auf das Bild genommen werden:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oPic = oDoc.getElementById(\"bild\")<\/pre>\n<p>Die Objektvariable <b>oPic<\/b> ist wieder einmal im Kopf des Moduls deklariert und spiegelt das Bild-Objekt wieder:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oPic<span style=\"color:blue;\"> As <\/span>HTMLImg<\/pre>\n<p>Die Typklasse <b>HTMLImg<\/b> finden Sie abermals in der Bibliothek <b>MSHTML<\/b>. &Uuml;ber die Variable <b>oPic<\/b> kann in der Folge auf s&auml;mtliche Eigenschaften des Bilds Einfluss genommen werden!<\/p>\n<p>Bevor die Routine das tut, wird erst &uuml;ber <b>NewRecord<\/b> ermittelt, ob es sich um einen neuen Datensatz im Formular handelt. Dann n&auml;mlich ist weiter nichts zu tun und die Routine wird verlassen. Andernfalls blickt der Code auf das Datenfeld <b>Binear<\/b>. Ist es bereits mit Bilddaten gef&uuml;llt, so verzweigt die Routine entsprechend. &acute;Die Sichtbarkeit einiger Labels wird eingestellt und die Datengr&ouml;&szlig;e aus <b>Len(Me!Binear)<\/b> erhalten. Die Beschriftung des Labels zur Anzeige dieser Gr&ouml;&szlig;e wird &uuml;ber die <b>Format<\/b>-Funktion versch&ouml;nert. Sind noch keine Bilddaten angelegt, so setzt der Code den Inhalt des HTML-Bildobjekts <b>oPic<\/b> auf den Dateipfad:<\/p>\n<pre>oPic.src = Me!Datei.Value<\/pre>\n<p>Falls doch, so wird der gleichen Eigenschaft der komplette Inhalt des <b>Memo<\/b>-Felds zugewiesen:<\/p>\n<pre>oPic.src = Me!Binaer.Value<\/pre>\n<p><b>src<\/b> entspricht in etwa der <b>URL<\/b> des Bildelements (<b>href<\/b>). Das Zuweisen dieses Eigenschaftswerts f&uuml;hrt wieder zum Neurendern des Dokuments im Browser. Das kann asynchron durchaus einige Zeit beanspruchen, weshalb auch hier eine &auml;hnliche Schleife eingebaut ist, die den Zustand des Bilds abfragt.<\/p>\n<p>Gibt die Eigenschaft <b>ReadyState<\/b> des Bildobjekts den String <b>complete<\/b> zur&uuml;ck, so ist das Bild fertig dargestellt. Abschlie&szlig;end werden noch die Abmessungen des Bilds f&uuml;r die weitere Verwendung in den Variablen <b>wPic<\/b> und <b>hPic<\/b> (Breite, H&ouml;he) zwischengespeichert und die Routine <b>chkScale_AfterUpdate<\/b> aufgerufen, die auch beim Aktivieren oder Deaktivieren der Checkbox <b>Originalgr&ouml;&szlig;e<\/b> (<b>chkScale<\/b>) im Formular ausgel&ouml;st wird. Mehr braucht es f&uuml;r die Anzeige des Bilds im Webbrowser-Steuerelement zun&auml;chst nicht!<\/p>\n<h2>Kontextmen&uuml; steuern<\/h2>\n<p>Der erweiterte Code f&uuml;r das Ereignis <b>oncontextmenu<\/b> der Dokumentvariablen <b>oDoc<\/b> steht in Listing 4. Das Ereignis wird grunds&auml;tzlich bei Rechtsklick auf das Dokument ausgel&ouml;st. Der Code ermittelt nun, auf welchen Koordinaten dieser Klick geschah. Dazu befragt es das Elternobjekt des Dokuments vom Typ <b>HTMLWindow<\/b>. Dieses Objekt kennt eine Objekt-Eigenschaft <b>event<\/b>, die alle Ereignisse des Browser-Fensters vereint. In <b>x<\/b> und <b>y<\/b> stehen darin die Koordinaten des Klicks. Die Funktion <b>elementFromPoint<\/b> gibt zur&uuml;ck, welches Element sich an diesen Koordinaten befindet. Handelt es sich um unser Bild, das ja die <b>ID<\/b> <b>bild<\/b> besitzt, so aktiviert sich das Kontextmen&uuml;, indem der R&uuml;ckgabewert der Prozedur auf <b>True<\/b> gesetzt wird.<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oDoc_oncontextmenu()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>x<span style=\"color:blue;\"> As Long<\/span>, y<span style=\"color:blue;\"> As Long<\/span>\r\n     x = oDoc.parentWindow.event.x\r\n     y = oDoc.parentWindow.event.y\r\n     <span style=\"color:blue;\">If <\/span>oDoc.elementFromPoint(x, y).ID = \"bild\"<span style=\"color:blue;\"> Then<\/span>\r\n         oDoc_oncontextmenu = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p class='imagetext'>Listing 4: Aktivieren des Kontextmen&uuml;s in Abh&auml;ngigkeit vom angeklickten Element des Webdokuments<\/p>\n<h2>Ereignisse des Bildobjekts<\/h2>\n<p>Die Variable <b>oPic<\/b> vom Typ <b>HTMLImg<\/b> wurde ja ebenfalls mit der Auszeichnung <b>WithEvents<\/b> deklariert. Auch das HTML-Bild kann Ereignisse ausl&ouml;sen! Wir verwenden zur Demonstration das <b>onclick<\/b>-Ereignis, das beim Anklicken des Bilds hervorgerufen wird:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oPic_onclick()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">MsgBox<\/span> oPic.src, vbInformation\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Dabei muss hier nicht ermittelt werden, welche Maustaste bedient wurde, denn bei der rechten zeigt sich ohnehin das Kontextmen&uuml;. Die <b>Msgbox<\/b> gibt die Eigenschaft <b>src<\/b> des Bildobjekts aus, die zuvor in der Ereignisprozedur <b>Beim Anzeigen<\/b> des Formulars zugewiesen wurde. Neben diesem Ereignis kann das Bildobjekt noch etwa 50 weitere ausl&ouml;sen, wie ein Blick in den Objektkatalog verr&auml;t!<\/p>\n<h2>Bild beeinflussen<\/h2>\n<p>Sie m&ouml;chten das Bild im Browser ver&auml;ndern Das geht verbl&uuml;ffend einfach &uuml;ber die <b>style<\/b>-Eigenschaft des Bildobjekts <b>oPic<\/b>. Sie k&ouml;nnen es etwa um 90 Grad nach rechts drehen, falls die Aufnahme dies erfordert. Dann setzen Sie lediglich dieses Statement ab:<\/p>\n<pre>oPic.Style.Transform = \"rotate(90deg)\"<\/pre>\n<p>Linksseitig geht es damit:<\/p>\n<pre>oPic.Style.Transform = \"rotate(-90deg)\"<\/pre>\n<p>Oder Sie spiegeln es horizontal:<\/p>\n<pre>oPic.Style.Transform = \"scaleX(-1)\"<\/pre>\n<p>Das vertikale Pendant:<\/p>\n<pre>oPic.Style.Transform = \"scaleY(-1)\"<\/pre>\n<p>Die Buttons im Fu&szlig;bereich des Formulars l&ouml;sen diese Anweisungen aus. Dabei wird allerdings zuvor jeweils  diese Zeile abgesetzt:<\/p>\n<pre>oPic.Style.Transform = \"initial\"<\/pre>\n<p>Das bewirkt, dass das Bild sich wieder in den Ausgangszustand zur&uuml;ckbegibt. Dasselbe erreichen Sie auch mit folgendem Befehl:<\/p>\n<pre>oPic.Style.Transform = \"\"<\/pre>\n<p>Hier wird deutlich, dass sich diese Beeinflussung nur auf die Anzeige im Browser bezieht, nicht aber auf das Bild selbst. Speichern etwa Sie das rotierte Bild ab, so hat sich der Transform nicht auf die Datei ausgewirkt. Eine Bildbearbeitung ist auf diese Weise nicht so einfach zu erreichen, obwohl die style- und transform-Eigenschaften unersch&ouml;pfliche M&ouml;glichkeiten anbieten. Wichtiger, als die eben besprochenen Effekte ist sicher das Skalieren des Bilds, falls es gr&ouml;&szlig;er ist, als das Webbrowser Control im Formular, wie in Bild 12.<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/igel_large.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/igel_large.png\" alt=\"Ist das geladene Bild gr&ouml;&szlig;er, als das Webbrowser-Control, so entstehen ohne weiteres Zutun f&uuml;r das Dokument automatisch Scroll-Balken\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 12: Ist das geladene Bild gr&ouml;&szlig;er, als das Webbrowser-Control, so entstehen ohne weiteres Zutun f&uuml;r das Dokument automatisch Scroll-Balken<\/p>\n<p>Deaktivieren Sie das Kontrollk&auml;stchen <b>Originalgr&ouml;&szlig;e<\/b> im Formularfu&szlig;, so passt sich das Bild, je nach Breite und H&ouml;he, genau in den sichtbaren Bereich des Dokuments ein (siehe Bild 13).<\/p>\n<p class=\"image\"><a rel=\"lightbox\" href=\"..\/tl_files\/images\/igel_scaled.png\"><img decoding=\"async\" src=\"..\/tl_files\/images\/igel_scaled.png\" alt=\"Nach Deaktivieren des Kontrollk&auml;stchens skaliert sich das Bild passend im Web-Dokument\" width=\"325\" \/><\/a><\/p>\n<p class='imagetext'>Bild 13: Nach Deaktivieren des Kontrollk&auml;stchens skaliert sich das Bild passend im Web-Dokument<\/p>\n<p>Die Ereignisroutine <b>chkScale_AfterUpdate<\/b> (siehe Listing 5) &uuml;bernimmt diese Anpassung. In den modulweit deklarierten Variablen <b>wPic<\/b> und <b>hPic<\/b> speicherten wir bereits beim Laden des Bilds dessen Abmessungen. Hier werden sie nun verwendet, um aus dem Seitenverh&auml;ltnis den Skalierungsfaktor zu errechnen. Die Breite und H&ouml;he des Browser-Fensters (in <b>w<\/b> und <b>h<\/b>) erh&auml;lt man aus der Objektvariablen <b>oBrowser<\/b> und deren Eigenschaften <b>Width<\/b> und <b>Height<\/b>. Das ist &uuml;brigens ein Trick! Denn das Webbrowser-Steuerelement <b>ctlWeb<\/b> wurde mit dem <b>Verankern<\/b>-Feature versehen, weshalb es seine Gr&ouml;&szlig;e dem Formular anpasst. Leider geben alle Steuerelemente dann in <b>Width<\/b> und <b>Height<\/b> nicht etwa die angepassten Abmessungen wieder, sondern die des Entwurfs. Sie k&ouml;nnen die <b>verankerte<\/b> Gr&ouml;&szlig;e eines Controls in VBA nicht ohne API-Funktionen ermitteln! ActiveX-Steuerelemente, wie der Webbrowser, werden von Access automatisch in die tats&auml;chliche Gr&ouml;&szlig;e des zugrundeliegenden Controls eingepasst. Also lesen wir einfach dessen Gr&ouml;&szlig;e aus, was hier &uuml;ber die Objektvariable <b>oBrowser<\/b> geschieht. Zwar k&ouml;nnte man etwa auch &uuml;ber die tats&auml;chliche Breite des Formulars (<b>InsideWidth<\/b>) abz&uuml;glich der Breite des Controls im Entwurf und einem Offset ebenfalls seine Breite bestimmen, aber unser Weg ist einfacher. Wie auch immer, die ge&auml;nderten Abmessungen des Bilds im Browser k&ouml;nnen nun &uuml;ber die Eigenschaften <b>Width<\/b> und <b>Height<\/b> auf die Bildvariable <b>oPic<\/b> neu gesetzt werden. <\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>chkScale_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>w<span style=\"color:blue;\"> As Long<\/span>, h<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>factor<span style=\"color:blue;\"> As Double<\/span>\r\n     \r\n     <span style=\"color:blue;\">If <\/span>chkScale = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         oPic.Width = wPic: oPic.Height = hPic\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         w = oBrowser.Width: h = oBrowser.Height\r\n         <span style=\"color:blue;\">If <\/span>(w \/ h) > (wPic \/ hPic)<span style=\"color:blue;\"> Then<\/span>\r\n             factor = h \/ hPic\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             factor = w \/ wPic\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         oPic.Width = wPic * factor - 20\r\n         oPic.Height = hPic * factor - 16\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p class='imagetext'>Listing 5: Routine zum optionalen Skalieren des Bilds<\/p>\n<p>Fazit: Sie ben&ouml;tigen weder ausf&uuml;hrliche <b>HTML<\/b>-Kenntnisse, noch <b>Javascript<\/b>, um Elemente im Webbrowser-Control zu steuern. Praktisch alles l&auml;sst sich &uuml;ber die Objektklassen der <b>MSHTML<\/b>-Bibliothek erledigen. &Uuml;brigens reflektieren sich solche Aktionen auf die Elementobjekte dennoch im zugrundeliegenden <b>HTML<\/b>-Code. Rotieren Sie das Bild einfach einmal mit dem entsprechenden Button und lassen Sie sich danach den Quelltext des Dokuments ausgeben. Setzen Sie dazu etwa diese Zeile im VBA-Direktfenster ab:<\/p>\n<pre> Forms!frmBilder!ctlWeb.Object.Document.all(0).outerHTML<\/pre>\n<p>Das Ergebnis:<\/p>\n<pre><html><head><\/head><body><img loading=\"lazy\" decoding=\"async\" width=\"267\" height=\"277\" id=\"bild\" style=\"transform: rotate(90deg);\" alt=\"fehlt!\" src=\"data: \r\n...<\/img><\/body><\/html><\/pre>\n<h2>Kodieren der Bilddaten<\/h2>\n<p>Bisher haben wir nur den Umgang mit einem existierenden Bild beschrieben, das entweder als Datei oder bin&auml;r in den Daten des Memo-Felds vorliegt. Wie aber bekommen Sie diese Daten aus einer Datei in das Memo-Feld Schauen Sie sich dazu den zweiten Teil der Ereignisprozedur beim Klick auf den Laden-Button an (siehe Listing 6).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdLoad_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>sExt<span style=\"color:blue;\"> As String<\/span>, sPrefix<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     \r\n     ...\r\n     bin = FileContent(Me!txtDatei.Value)\r\n     Select Case sExt\r\n     <span style=\"color:blue;\">Case <\/span>\"jpg\", \"jpeg\": sPrefix = \"data:image\/jpeg;base64,\"\r\n     <span style=\"color:blue;\">Case <\/span>\"png\": sPrefix = \"data:image\/png;base64,\"\r\n     <span style=\"color:blue;\">Case <\/span>\"bmp\": sPrefix = \"data:image\/bitmap;base64,\"\r\n     <span style=\"color:blue;\">Case <\/span>\"tif\": sPrefix = \"data:image\/tiff;base64,\"\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     oPic.src = sPrefix & EncodeBase64(bin)\r\n     Me!Binaer.Value = oPic.src\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p class='imagetext'>Listing 6: Beim Laden einer Bilddatei &uuml;ber den Button cmdLoad spielt sich diese Prozedur ab (zweiter Teil)<\/p>\n<p>Hier werden zwei Hilfsfunktionen angesprochen. Die eine nennt sich <b>FileContent<\/b> (siehe Listing 7) und speichert eine als String-Parameter &uuml;bergebene Datei in ein Byte-Array (<b>bin<\/b>). Sie verwendet dazu die <b>Open<\/b>-Methode von VBA. Danach wird &uuml;ber die Endung der Datei, welche in <b>sExt<\/b> abgespeichert wurde, in einem <b>Select-Case<\/b>-Block der HTML-<b>MIME<\/b>-Typ festgelegt und der Variablen <b>sPrefix<\/b> zugewiesen. Kommt ein Bild nicht aus einer Datei, sondern aus bin&auml;ren Daten, so hat der Inhalt der <b>src<\/b>-Eigenschaft nicht mit dem Pr&auml;fix <b>file:<\/b> zu beginnen, sondern mit <b>data:<\/b>, gefolgt vom <b>MIME<\/b>-Typ. Dabei wird nur eine <b>base64<\/b>-Kodierung unterst&uuml;tzt, wie Sie das eventuell auch aus dem Quelltext von E-Mails mit Bildern kennen.<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>FileContent(sFile<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Byte<\/span>()\r\n     <span style=\"color:blue;\">Dim <\/span>F<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     \r\n     F = FreeFile\r\n     Open sFile For Binary Access Read<span style=\"color:blue;\"> As <\/span>F\r\n     ReDim bin(LOF(F) - 1)\r\n     Get F, , bin\r\n     Close F\r\n     FileContent = bin\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p class='imagetext'>Listing 7: &Uuml;berf&uuml;hren eines Dateiinhalts in ein Byte-Array<\/p>\n<p>Aufgabe ist es nun, den Inhalt des Byte-Arrays <b>bin<\/b> in einen solchen <b>base64<\/b>-String zu verwandeln. Hier kommt die zweite Hilfsroutine mit dem Namen <b>EncodeBase64<\/b> ins Spiel (siehe Listing 8). Die Konvertierung von Daten nach <b>base64<\/b> ist keine triviale Aufgabe und verlangt &uuml;blicherweise nach recht komplexem seitenlangen VBA-Code. Tats&auml;chlich ist die Angelegenheit verbl&uuml;ffend einfach, wenn man sich Objekte der <b>XML<\/b>-Bibliothek von Microsoft zunutze macht. Dazu setzen Sie abermals einen Verweis auf die Bibliothek <b>Microsoft XML, v 6.0<\/b> (im Objektkatalog dann <b>MSXML2<\/b>), die Bestandteil von Windows ist. <\/p>\n<pre><span style=\"color:blue;\">Function <\/span>EncodeBase64(bin()<span style=\"color:blue;\"> As Byte<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>oXML<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> MSXML2.DOMDocument\r\n     <span style=\"color:blue;\">Dim <\/span>oElem<span style=\"color:blue;\"> As <\/span>MSXML2.IXMLDOMElement\r\n     <span style=\"color:blue;\">Set<\/span> oXML = <span style=\"color:blue;\">New<\/span> MSXML2.DOMDocument\r\n     <span style=\"color:blue;\">Set<\/span> oElem = oXML.createElement(\"tmp\")\r\n     <span style=\"color:blue;\">With<\/span> oElem\r\n         .DataType = \"bin.base64\"\r\n         .NodeTypedValue = bin\r\n         EncodeBase64 = .Text\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p class='imagetext'>Listing 8: Hilfsfunktion zum Kodieren in base64 &uuml;ber XML<\/p>\n<p>Die Routine erzeugt zun&auml;chst ein neues XML-Dokument in der Objektvariablen <b>oXML<\/b> und legt dann ein nicht typisiertes XML-Element <b>oElem<\/b> mit dem Namen <b>tmp<\/b> in ihm an. Zwei Eigenschaften dieses Objektelements werden nun gesetzt: Der Datentyp (<b>bin.base64<\/b>) und der Inhalt &uuml;ber <b>NodeTypedValue<\/b>. Das war&#8217;s auch schon! &Uuml;ber die Eigenschaft <b>Text<\/b> k&ouml;nnen Sie nun die Textinterpretation der Bin&auml;rdaten als String auslesen. Dieser String wird in Listing 6 mit dem Pr&auml;fix <b>sPrefix<\/b> zusammengesetzt und abschlie&szlig;end dem Bildobjekt als <b>Source<\/b> (<b>src<\/b>) zugewiesen. Der Browser rendert daraufhin sofort das Bild. Au&szlig;erdem speichert die letzte Zeile noch den <b>src<\/b>-String im Formularfeld <b>Binaer<\/b>. Die Bilddaten befinden sich damit in der Tabelle und k&ouml;nnen beim n&auml;chsten Mal anstatt der Datei f&uuml;r die Bildanzeige benutzt werden.<\/p>\n<p>&Uuml;brigens ben&ouml;tigen die Bilddaten in der <b>base64<\/b>-Kodierung nicht viel mehr Speicherplatz, als die Ursprungsdateien. Aus einem <b>JPG<\/b> mit 100 Kilobyte wird ungef&auml;hr ein String von 130 Kilobyte. Das ist akzeptabel und kann mit dem Speicherbedarf von Anlagefeldern mithalten. Im Modul <b>mdlBase64<\/b> der Beispieldatenbank ist noch eine Funktion <b>DecodeBase64<\/b> enthalten, die einen <b>base64<\/b>-String in ein Byte-Array zur&uuml;ckverwandeln kann. Sie verwendet ebenfalls <b>XML<\/b>-Objekte. In der Datenbank findet sie allerdings keine Verwendung, weshalb auf ein Listing hier verzichtet wird. Falls Sie dennoch Interesse an ihr haben, dann ist die Information wichtig, dass als Parameter nicht der komplette Inhalt des Binaer-Felds zu &uuml;bergeben werden muss, sondern nur der Teil nach dem <b>MIME<\/b>-Pr&auml;fix, also nach dem ersten Komma.<\/p>\n<h2>Modifizierung des Webbrowser Controls<\/h2>\n<p>Damit die Bildanzeige im Webbrowser-Steuerelement ordnungsgem&auml;&szlig; funktioniert, sollte es die Version <b>11<\/b> des Internet Explorers offenbaren. Dazu reicht leider nicht, dass dieser auch installiert ist. Microsoft versetzt das Webbrowser-Steuerelement unmodifiziert immer in den Modus der Version <b>7<\/b>, egal, ob etwa auch <b>Edge<\/b> installiert ist. Um das aufzuheben, muss beim Start der Datenbank die Prozedur <b>PrepareBrowser<\/b> im Modul <b>mdlWebControl<\/b> aufgerufen werden, die einige Einstellungen f&uuml;r den gehosteten Internet Explorer vornimmt. In der Beispieldatenbank geschieht dies beim &Ouml;ffnen des Intro-Formulars <b>frmIntro<\/b>.<\/p>\n<p>Auf eine Beschreibung des Moduls k&ouml;nnen wir an dieser Stelle verzichten. Es kam bereits im Beitrag <b>Google- und Bing-Maps<\/b> im Formular (Ausgabe <b>03\/2016<\/b>) zur Anwendung. Dort sind seine Funktionsweise und die Gr&uuml;nde f&uuml;r den Einsatz eingehend erl&auml;utert worden. F&uuml;r den vorliegenden Zweck erweiterten wir es nur geringf&uuml;gig.<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Mit dem Webbrowser-Steuerelement haben Sie ein interessantes Instrument in der Hand, um Bilder in Formularen ohne Dateien direkt aus Tabellen anzuzeigen. Der daf&uuml;r ben&ouml;tigte Code h&auml;lt sich in Grenzen. Der Clou der L&ouml;sung besteht vor allem darin, dass Sie diese Web-Bilder &uuml;ber die <b>style<\/b>-Methoden auf einfache Weise in ihrer Gestalt steuern k&ouml;nnen.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>1702_BildWeb.zip<\/p>\n<p><a href=\"..\/Downloads\/Beispiele\/{9D00A3C8-934D-4EB5-9936-63D3C0A72D0A}\/BildanzeigeWeb.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Handhabung von Bildern in Formularen war und ist ein Dauerbrennerthema in vielen Foren. Das genuine Bildsteuerelement von Access weist auch in der zeitweilig modernisierten Version etliche Beschr&auml;nkungen auf. Das Anlage-Steuerelement ist zwar pfiffig, aber dessen Programmierung f&auml;llt reichlich umst&auml;ndlich aus. Doch zu unserem Favoriten haben wir schon fr&uuml;her einmal ein alternatives Steuerelement auserkoren: das Webbrowser Control.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66022017,662017,44000015],"tags":[],"class_list":["post-55000349","post","type-post","status-publish","format-standard","hentry","category-66022017","category-662017","category-Interaktiv"],"aioseo_notices":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v15.9.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Der Webbrowser als Bildanzeige - Access [basics]<\/title>\n<meta name=\"description\" content=\"Die Handhabung von Bildern in Formularen war und ist ein Dauerbrennerthema in vielen Foren. Das genuine Bildsteuerelement von Access weist auch in der zeitweilig modernisierten Version etliche Beschr\u00e4nkungen auf. Das Anlage-Steuerelement ist zwar pfiffig, aber dessen Programmierung f\u00e4llt reichlich umst\u00e4ndlich aus. Doch zu unserem Favoriten haben wir schon fr\u00fcher einmal ein alternatives Steuerelement auserkoren: das Webbrowser Control.\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Der Webbrowser als Bildanzeige - Access [basics]\" \/>\n<meta property=\"og:description\" content=\"Die Handhabung von Bildern in Formularen war und ist ein Dauerbrennerthema in vielen Foren. Das genuine Bildsteuerelement von Access weist auch in der zeitweilig modernisierten Version etliche Beschr\u00e4nkungen auf. Das Anlage-Steuerelement ist zwar pfiffig, aber dessen Programmierung f\u00e4llt reichlich umst\u00e4ndlich aus. Doch zu unserem Favoriten haben wir schon fr\u00fcher einmal ein alternatives Steuerelement auserkoren: das Webbrowser Control.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\" \/>\n<meta property=\"og:site_name\" content=\"Access [basics]\" \/>\n<meta property=\"article:published_time\" content=\"2017-04-01T00:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"-0001-11-30T00:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/..\/tl_files\/images\/tblBilder1.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Gesch\u00e4tzte Lesezeit\">\n\t<meta name=\"twitter:data1\" content=\"22\u00a0Minuten\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/access-basics.de\/#website\",\"url\":\"https:\/\/access-basics.de\/\",\"name\":\"Access [basics]\",\"description\":\"DAS ACCESS-MAGAZIN F\\u00dcR ALLE, DIE VON 0 AUF 100 WOLLEN\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/access-basics.de\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html#primaryimage\",\"inLanguage\":\"de\",\"url\":\"http:\/\/vg08.met.vgwort.de\/na\/1a6c214b72ca489c86ed5ce7d397c30c\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html#webpage\",\"url\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\",\"name\":\"Der Webbrowser als Bildanzeige - Access [basics]\",\"isPartOf\":{\"@id\":\"https:\/\/access-basics.de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html#primaryimage\"},\"datePublished\":\"2017-04-01T00:00:00+00:00\",\"dateModified\":\"-0001-11-30T00:00:00+00:00\",\"author\":{\"@id\":\"https:\/\/access-basics.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f\"},\"description\":\"Die Handhabung von Bildern in Formularen war und ist ein Dauerbrennerthema in vielen Foren. Das genuine Bildsteuerelement von Access weist auch in der zeitweilig modernisierten Version etliche Beschr\\u00e4nkungen auf. Das Anlage-Steuerelement ist zwar pfiffig, aber dessen Programmierung f\\u00e4llt reichlich umst\\u00e4ndlich aus. Doch zu unserem Favoriten haben wir schon fr\\u00fcher einmal ein alternatives Steuerelement auserkoren: das Webbrowser Control.\",\"breadcrumb\":{\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/access-basics.de\/\",\"url\":\"https:\/\/access-basics.de\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\",\"url\":\"https:\/\/access-basics.de\/index.php\/Der_Webbrowser_als_Bildanzeige.html\",\"name\":\"Der Webbrowser als Bildanzeige\"}}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/access-basics.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/access-basics.de\/#personlogo\",\"inLanguage\":\"de\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/posts\/55000349","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/comments?post=55000349"}],"version-history":[{"count":0,"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/posts\/55000349\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/media?parent=55000349"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/categories?post=55000349"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-basics.de\/index.php\/data\/wp\/v2\/tags?post=55000349"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}