Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
Wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen können, beleuchtete bereits unser Beitrag „HTML5 als Grafikkomponente“. Dass sich mit diesem Gespann aber Bilder auch interaktiv anlegen lassen, zeigen wir in diesem zweiten Teil anhand einer kleinen Zeichenanwendung, die ohne externe Komponenten auskommt.
Referenz
Die Ausführungen dieses Beitrags setzen jene aus dem Artikel HTML5 als Grafikkomponente fort. Dort sind die Grundlagen zum Einsatz des Webbrowser-Steuerelements im Verein mit HTML5 beschrieben, auf die hier nicht noch einmal eingegangen wird.
MS Access als Malprogramm
Bilder und Grafiken scheinen, wie man den Beiträgen verschiedener Foren entnehmen kann, für Access-Entwickler ein immer wiederkehrendes Thema zu sein. Sicher ist die Anzeige von Bilddateien in Formularen und Berichten, sei es über das Laden aus dem System, über OLE-Objekte oder Anlagefelder, eine häufige Anforderung. Das reicht vom Logo im Berichtskopf über ein Konterfei im Mitarbeiterdatensatz bis hin zu technischen Zeichnungen. Gerade für letztere eignet sich HTML5 gut, weil Sie hier eben nicht nur statisch Grafiken aus Dateien laden können, sondern in diese per VBA zusätzliche Elemente einbauen können. Oder Sie erstellen die Grafiken komplett neu, wie die Diagramme im Beitrag HTML5 als Grafikkomponente zeigen.
Das Problem bei HTML5 ist allerdings, dass die erzeugten Grafiken gerenderte Bitmaps sind, auf deren Elemente Sie später keinen Einfluss mehr haben. Ein Undo ist schlecht realisierbar. Möglich ist aber die sequenzielle Bearbeitung der Grafik, die auch interaktiv geschehen kann. Eben davon macht unser Malprogramm Gebrauch.
Doch wer erstellt unter Access überhaupt Gemälde Ein Beispiel wären technische Zeichnungen, die vervollständigt werden. Als Anbieter von Raumausstattungen etwa könnten Sie einen Raum gestalten lassen, indem Sie dessen leere Ansicht laden und in diese interaktiv mit der Maus Elemente hineinziehen und positionieren.
Sie besitzen ein mobiles Gerät, wie etwa ein Windows-Tablet Dann können Sie mit diesem etwa jene Terminals von DHL oder DPD nachbilden und in den Grafikbereich eines Formulars Unterschriften eingeben lassen, um sie in Tabellen abzuspeichern.
Günstig sind in diesem Fall jedenfalls Geräte mit einem Touch-Screen, seien es Tablets oder Laptops. Natürlich erweitert ein Grafiktablett Ihren PC ebenfalls entsprechend.
Malen im Formular
Nach dem Start der Beispieldatenbank HTMLImage2.accdb finden Sie das Formular frmHTML5Draw zur Laufzeit vor, wie in Bild 1. Hier können Sie pro Datensatz ein Bild anzeigen lassen oder zeichnen. Ist ein Bild gespeichert, so wird es automatisch aus einer Tabelle geladen, während bei einem neuen Datensatz ein leeres Blatt auf Sie wartet. Wenden wir uns zunächst den Funktionen des Formulars und seiner Steuerelemente zu.
Bild 1: So präsentiert sich die Malanwendung im Formular frmHTML5Draw der Beispieldatenbank mit einer bereits geladenen Grafik
Die Grafikfläche im Detailbereich besteht aus einem Webbrowser-Steuerelement, in dessen Eigenschaft URL der String =“about:blank“ hinterlegt ist, damit es keinen Navigationsfehler ausgibt, sondern eine weiße Fläche. Der Zeichnung können Sie oben einen Namen geben, der sie eindeutig identifiziert. Zeichnung und Namen gelangen beide in eine Tabelle, an die das Formular gebunden ist. Das Speichern geschieht allerdings nicht automatisch mit Verlassen des Datensatzes, sondern nur mit Klick auf den Button Bild speichern. Alternativ kann die Grafik auch in eine Datei exportiert werden, wobei Ihnen die Formate PNG und JPG zur Auswahl stehen, welche Sie mit den beiden Checkboxen einstellen. übrigens beeinflusst diese Auswahl auch die interne Speicherung des Bilds in der Tabelle. Das Label rechts oben gibt Auskunft über den dafür benötigten Speicherbedarf.
Mit der Maus zeichnen Sie nun in die Grafikfläche. Die Farbe des Stifts stellen Sie mit Klick auf das Rechteck Malfarbe ein, die Füllung einer Figur mit dem Rechteck Füllfarbe und einen etwaigen Schattenwurf der Linien mit der Schattenfarbe. Der Klick auf diese Rechtecke ruft jeweils den Windows-Farbauswahldialog auf (Bild 2). In der Combobox Strichbreite wählen Sie die gewünschte Dicke des Stifts aus und dessen Deckkraft in der Combobox Alpha. Stellen Sie Schatten auf einen Wert größer als 0 ein, so wird die gemalte Linie zusätzlich mit einem Drop Shadow hinterlegt, einem Verlaufsschatten, dessen Radius dem gewählten Wert entspricht.
Bild 2: Farbauswahldialog von Windows zur Einstellung der Farben
Diese Einstellungen wirken sich jeweils auf den nächsten Zeichenvorgang aus. Malen Sie nun etwa einen Kringel, der nicht unbedingt geschlossen sein muss. Mit Klick auf die Schaltfläche Figur schließen geschieht dies jedoch automatisch. Ein weiterer Klick auf den nun aktivierten Button Figur füllen versieht die jetzt umrandete Fläche mit der Füllfarbe. Sowohl Linien, wie Schatten und Füllungen berücksichtigen dabei die in Alpha eingestellte Transparenz. Sie können somit überlagernd malen!
Ein Klick auf den Toggle-Button Malen ändert dessen Beschriftung in Radieren. Nun können Sie mit der Maus Teile der Zeichnung ausradieren, was technisch so gelöst ist, dass einfach mit weißer Farbe ohne Transparenz und mit einer Stiftbreite von etwa 10 Pixeln gemalt wird. Ein weiterer Klick auf den Button stellt den vorigen Malmodus wieder her.
Sie können auch ein externes Bild in die Grafik laden, indem Sie den Dateiauswahldialog über den Button Ext. Bild laden… aufrufen. Die Position des eingefügten Bilds können Sie damit allerdings eben so wenig beeinflussen, wie dessen Skalierung. Das hätte einigen zusätzlichen Aufwand erfordert, den wir uns erspart haben. Wohl aber beeinflusst wieder der Wert von Alpha, wie transparent das Bild eingefügt wird.
Dass die Qualität der Zeichnung etwas zu wünschen übrig lässt, können Sie der Abbildung entnehmen. Mit der Maus ist das Malen gar nicht so einfach. Zudem kommen die Linien etwas krakelig daher, was weniger an HTML5 liegt, das Antialiasing durchaus unterstützt, sondern am eingesetzten Verfahren. Das wollten wir so einfach halten, wie möglich: Bei jeder Mausbewegung wird zwischen den beiden abgetasteten Punkten eine einzelne Linie mit der lineTo-Anweisung des HTML5-Canvas erzeugt. Deshalb sind Bögen nicht wirklich rund, sondern weisen an den Punkten Kantensprünge auf, die zu einer vermeintlichen Rasterung führen. Sollte das vermieden werden, so müssten mehrere Abtastpunkte in einer Bezier-Linie (bezierCurveTo) zusammengeführt werden, was den Aufwand deutlich erhöht hätte.
Tabelle als Grafikspeicher
Damit die Zeichnungen nicht nur in Dateien abgespeichert werden können, gibt es die Tabelle tblBilderDraw, deren Aufbau Bild 3 verdeutlicht. Neben dem Namen der Zeichnung in BildName und dem Autowert ID gibt es hier nur ein OLE-Feld BildOLE, in das indessen keineswegs OLE-Objekte hineinkommen, sondern reine Binärdaten, die exakt der Datei entsprechen, die Sie auch extern abspeichern würden.
Bild 3: Die Tabelle tblBilderDraw speichert nur die gemalten Grafiken und ihren Namen neben der ID
Im Formular ist lediglich der BildName direkt an die entsprechende Textbox gebunden. Das Webbrowser-Steuerelement ist natürlich ungebunden, denn mit den Binärdaten kann es nichts anfangen. Das Laden und Schreiben der Browser-Daten müssen VBA-Routinen übernehmen.
Vorgänge beim Laden und Anzeigen des Formulars
Ein Teil des gerade einmal 250 Zeilen langen Formular-Codes läuft beim öffnen (Form_Load) und im Ereignis Beim Anzeigen (Form_Current) ab. Form_Load stellt lediglich den Formularzeitgeber auf 100 ms ein:
Me.TimerInterval = 100
Denn im Zeitgeberereignis steht die eigentliche Prozedur, die die initialen Vorgänge vornimmt. Auch Form_Current macht nicht viel mehr:
Me!ctlWeb.Object.Navigate2 "about:blank" ... Form_Timer
Sie ruft ebenfalls das Timer-Ereignis auf. Grund dafür ist ein Delay des Browsers ctlWeb beim Navigieren zu einer neuen URL, was asynchron abläuft und das Formular zuweilen durcheinanderbringt. Zwar ist das Steuerelement im Entwurf auf about:blank eingestellt, doch dies wirkt sich nur beim ersten Laden aus, nicht aber beim Ansteuern eines neuen Datensatzes. Hier muss das leere HTML-Dokument ausdrücklich erneut angelegt werden. Interessant ist damit vor allem die Ereignisprozedur Form_Timer. Ihre einzelnen Abschnitte folgen nun.
Me.TimerInterval = 0 Do While Me!ctlWeb.Object.ReadyState < 3 DoEvents Loop
Der Zeitgeber wird hier gleich wieder mit Setzen auf 0 deaktiviert, so dass es zu keinen Wiederholungen kommt. Anschließend wartet eine Schleife ab, bis die Eigenschaft ReadyState des Browsers mindestens den Wert 3 (readyStateInteractive) angenommen hat. Das dann der Fall, wenn der Browser die aufgerufene Seite fertiggestellt hat. Erst dann haben Sie Zugriff auf dessen HTML-Dokument. Das wird in der Folge der Formularvariablen oDoc zugewiesen:
Set oDoc = Me!ctlWeb.Object.Document
oDoc.body.setAttribute "bgColor", "#e0e0e0"
Zusätzlich stellt die Routine hier die Hintergrundfarbe des Dokument-Body auf hellgrau ein. Im Kopf des Formularmoduls sind noch einige weitere globale Variablen deklariert, auf die in anderen Prozeduren Bezug genommen wird:
Private WithEvents oDoc As HTMLDocument Private WithEvents oDiv As HTMLDivElement Private oCanvE As IHTMLCanvasElement Private CTX As ICanvasRenderingContext2D
Das HTML-Dokument steht also in oDoc. Der HTML5-Canvas kommt in die Elementvariablen oCanvE. Allerdings bauen wir das Canvas-Element nicht direkt in den Body des Dokuments ein, sondern in einen zusätzlichen DIV-Bereich, der gegebenenfalls verschoben werden kann. Die Variable oDiv nimmt einen Verweis auf diesen Bereich entgegen und ist außerdem mit dem Prädikat WithEvents versehen, wodurch dieser Ereignisse auslösen kann.
So etwa auch Mausereignisse, die wir später – Sie können es sich schon denken – dann zum Zeichnen auswerten werden. Und schließlich speichert die Variable CTX noch den Grafikkontext des Canvas, auf den erst ja die Zeichenanweisungen ausgeführt werden. Sie kennen das alles bereits aus dem ersten Beitrag zu HTML5.
Nun legt die Prozedur die HTML-Elemente im Dokument an und nimmt einige Grundeinstellungen für den Style des Canvas vor (Listing 1). Erst wird das DIV-Element erzeugt und dem Body hinzugefügt (appendChild). Dann generiert createElement einen neuen Canvas und weist ihn der modulglobalen Variablen oCanvE zu. Seine Id lautet zeichnung und seine Breite und Höhe werden fest auf die Abmessungen 600×400 festgelegt. Diese Werte für die Zeichenfläche können Sie natürlich nach Belieben modifizieren.
Private Sub Form_Timer() Dim oElement As IHTMLElement ... Set oDiv = oDoc.createElement("div1") oDiv.Id = "div1" oDoc.body.appendChild oDiv Set oCanvE = oDoc.createElement("canvas") oCanvE.Id = "zeichnung" oCanvE.Width = 600: oCanvE.Height = 400 oDiv.appendChild oCanvE Set CTX = oCanvE.getContext("2d") With CTX .globalAlpha = 1 .strokeStyle = 0 .lineWidth = 1 .FillStyle = "#ffffff" .fillRect 0, 0, 600, 400 .strokeRect 0, 0, 600, 400 .strokeStyle = ColorToStr(rColor.BackColor) .FillStyle = ColorToStr(rColorFill.BackColor) .shadowBlur = val(cbShadow.Value) .shadowColor = ColorToStr(rColorShadow.BackColor) .shadowOffsetX = .shadowBlur / 2 .shadowOffsetY = .shadowBlur / 2 .lineWidth = CSng(cbLineWidth.Value) End With ... End Sub
Listing 1: Die Timer-Prozedur initialisiert den HTML5-Canvas
Weiter geht es mit dem über getContext(2D“) ermittelten Grafikkontext des Canvas, den die Variable CTX entgegennimmt. Im With-Block auf sie werden nicht nur einige Style-Eigenschaften festgelegt, wie Hintergrund (FillStyle), Linienbreite (lineWidth) oder Schattenradius (shadowBlur), sondern auch gleich ein die Grafik umrahmendes Rechteck mit strokeRect gezeichnet.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo