{"id":55001309,"date":"2021-06-01T00:00:00","date_gmt":"2021-07-31T10:14:37","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1309"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Schaltflaechen_per_Code_anlegen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/","title":{"rendered":"Schaltfl&auml;chen per Code anlegen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Im Beitrag Schaltfl&auml;chen-Assistent (www.access-im-unternehmen.de\/1308) zeigen wir, wie Sie das Grundger&uuml;st eines Schaltfl&auml;chen-Assistenten definieren. Was Sie mit dem Schaltfl&auml;chen-Assistenten anfangen k&ouml;nnen, zeigen wir Ihnen im vorliegenden Beitrag. Wir wollen zun&auml;chst das Anlegen bestimmter Standardschaltfl&auml;chen erlauben. Die erste sind einfache OK- und Abbrechen-Schaltfl&auml;chen. Diese Aufgabe kostet in jedem Formular, das sie neu erstellen, ein paar Minuten. Zeit, die Sie sich sparen k&ouml;nnen &#8211; indem Sie einmalig Zeit in die Entwicklung eines passenden Steuerelement-Assistenten investieren.<\/b><\/p>\n<h2>Ziel des Assistenten<\/h2>\n<p>Das Ziel des Assistenten ist das Anlegen einer neuen <b>OK<\/b>-Schaltfl&auml;che. Dies soll folgende Eigenschaften umfassen:<\/p>\n<ul>\n<li>Schaltfl&auml;che mit einem Icon (zum Beispiel gr&uuml;ner Haken) und dem Text <b>OK <\/b>als Beschriftung<\/li>\n<li>Einstellen einiger Eigenschaften wie Rahmenart, Hintergrundfarbe, Gr&ouml;&szlig;e<\/li>\n<li>Hinzuf&uuml;gen einer Ereignisprozedur, die das Formular schlie&szlig;t oder alternativ andere Aktionen ausf&uuml;hrt<\/li>\n<\/ul>\n<h2>Grundger&uuml;st des Steuerelement-Assistenten<\/h2>\n<p>Das Grundger&uuml;st des Assistenten haben wir bereits im oben genannten Beitrag beschrieben. Dieses nutzen wir als Basis f&uuml;r die im vorliegenden Beitrag beschriebenen Techniken.<\/p>\n<p>Beim Starten des Steuerelement-Assistenten soll als Erstes ein Formular angezeigt werden, mit dem der Benutzer einige Einstellungen vornehmen kann, bevor er das Anlegen der Schaltfl&auml;che best&auml;tigt. Dieses Formular soll auch eine Vorschau der zu erstellenden Schaltfl&auml;che anzeigen.<\/p>\n<h2>Formular zum Anpassen der zu erstellenden Schaltfl&auml;che<\/h2>\n<p>F&uuml;r dieses Formular, das <b>frmButtonWizardOK <\/b>hei&szlig;en soll, stellen wir zun&auml;chst einige Eigenschaften ein. Die Eigenschaften <b>Datensatzmarkierer<\/b>, <b>Navigationsschaltfl&auml;chen<\/b>, <b>Trennlinien <\/b>und <b>Bildlaufleisten <\/b>sollen den Wert <b>Nein <\/b>erhalten, die Eigenschaft <b>Automatisch zentrieren <\/b>den Wert <b>Ja<\/b>.<\/p>\n<p>Au&szlig;erdem soll das Formular selbst eine <b>OK<\/b>-Schaltfl&auml;che sowie eine <b>Abbrechen<\/b>-Schaltfl&auml;che enthalten, damit der Benutzer die vorgenommenen &Auml;nderungen direkt anwenden oder auch verwerfen kann. Danach sieht das Formular wie in Bild 1 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_001.png\" alt=\"Erster Entwurf des Formulars zum Einstellen von Schaltfl&auml;chen-Eigenschaften\" width=\"549,559\" height=\"299,7594\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Erster Entwurf des Formulars zum Einstellen von Schaltfl&auml;chen-Eigenschaften<\/span><\/b><\/p>\n<h2>Beispiel-Schaltfl&auml;che<\/h2>\n<p>Nun wollen wir ja mit dem Formular festlegen, wie eine zu erstellende <b>OK<\/b>-Schaltfl&auml;che aussehen soll. Dazu f&uuml;gen wir Steuerelemente hinzu, mit denen wir die wichtigsten Einstellungen vornehmen. Diese haben wir in Bild 2 bereits hinzugef&uuml;gt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_002.png\" alt=\"Formular mit Steuerelementen zum Einstellen der Schaltfl&auml;cheneigenschaften\" width=\"574,559\" height=\"285,614\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Formular mit Steuerelementen zum Einstellen der Schaltfl&auml;cheneigenschaften<\/span><\/b><\/p>\n<p>Dies sind die Steuerelemente:<\/p>\n<ul>\n<li><b>txtBeschriftung<\/b>: Nimmt die Beschriftung f&uuml;r das Steuerelement entgegen.<\/li>\n<li><b>txtName<\/b>: Enth&auml;lt den Namen f&uuml;r das Steuerelement.<\/li>\n<li><b>cboBilder<\/b>: Zeigt die Namen der im Add-In verf&uuml;gbaren Bilder an. Diese Bilder werden in der Tabelle <b>MSysResources <\/b>gespeichert.<\/li>\n<li><b>chkTransparent<\/b>: Gibt an, ob der Hintergrund transparent angezeigt werden soll.<\/li>\n<li><b>cboBeschriftungAnzeigen<\/b>: Erlaubt die Auswahl der verschiedenen Anordnungen von Bild und Beschriftung oder auch nur die Anzeige eines Bildes.<\/li>\n<li><b>txtAbstandBildSchrift<\/b>: Erlaubt das Einf&uuml;gen von ein bis drei Leerzeichen zwischen Bild und Beschriftung.<\/li>\n<li><b>txtBildbreite<\/b>: Breite des Bildes in Pixel<\/li>\n<li><b>txtBildhoehe<\/b>: H&ouml;he des Bildes in Pixel<\/li>\n<li><b>cboEreignisprozeduren<\/b>: Dient der Auswahl der Anweisungen der Ereignisprozedur f&uuml;r die Schaltfl&auml;che.<\/li>\n<li><b>cmdEreignisprozedurenBearbeiten<\/b>: &Ouml;ffnet das Formular zum Bearbeiten der Ereignisprozeduren.<\/li>\n<\/ul>\n<p>Nat&uuml;rlich h&auml;tten wir noch einige weitere Eigenschaften aufnehmen k&ouml;nnen, aber das w&uuml;rde den Rahmen dieses Beitrags sprengen.<\/p>\n<h2>Wichtig: Option Compare Binary statt Option Compare Database<\/h2>\n<p>In einer Prozedur dieses Formulars wollen wir Umlaute in Vokale umwandeln. Die Replace-Funktion &auml;ndert bei Verwendung von <b>Option Compare Database <\/b>im Kopf des Moduls <b>&auml; <\/b>in <b>ae<\/b>, aber auch <b>&Auml; <\/b>in <b>ae<\/b>. Damit <b>&Auml; <\/b>in <b>Ae <\/b>ge&auml;ndert wird, stellen wir im Klassenmodul des Formulars <b>frmButtonWizard <\/b>die Anweisung <b>Option Compare Binary <\/b>ein:<\/p>\n<pre>Option Compare Binary\r\n<span style=\"color:blue;\">Option Explicit<\/span><\/pre>\n<h2>Hinzuf&uuml;gen einer Beschriftung<\/h2>\n<p>Das Eintragen einer Beschriftung ist der erste Schritt. Hierbei sollen direkt einige Aktionen erfolgen. Zum einen wollen wir dem Benutzer die Arbeit abnehmen, den Namen der Schaltfl&auml;che einzutragen.<\/p>\n<p>Daher soll dieser dynamisch basierend auf der Beschriftung generiert werden &#8211; mehr dazu weiter unten. Au&szlig;erdem soll die Gr&ouml;&szlig;e der Vorschau immer direkt an die enthaltene Beschriftung, gegebenenfalls mit Icon, angepasst werden.<\/p>\n<p>Da wir die Beschriftung auch noch in anderen Prozeduren ben&ouml;tigen, legen wir f&uuml;r diese eine modulweit deklarierte Variable namens <b>strBeschriftung <\/b>an:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>strBeschriftung<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p>Danach k&ouml;nnen wir in die Ereignisprozedur einsteigen, die aufgerufen wird, wenn der Benutzer den Text im Textfeld <b>txtBeschriftung <\/b>anpasst. Das l&ouml;st mit der Eingabe eines jeden Zeichens die Prozedur aus Listing 1 aus.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBeschriftung_Change()\r\n     <span style=\"color:blue;\">Dim <\/span>strText<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngPosLeer<span style=\"color:blue;\"> As Long<\/span>\r\n     strText = Me!txtBeschriftung.Text\r\n     strText = <span style=\"color:blue;\">Trim<\/span>(strText)\r\n     strBeschriftung = strText\r\n     Me!cmdBeispiel.Caption = strText\r\n     lngPosLeer = <span style=\"color:blue;\">InStr<\/span>(1, strText, \" \")\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> lngPosLeer = 0\r\n         strText = <span style=\"color:blue;\">Left<\/span>(strText, lngPosLeer - 1) & UCase(<span style=\"color:blue;\">Mid<\/span>(strText, lngPosLeer + 1, 1)) & <span style=\"color:blue;\">Mid<\/span>(strText, lngPosLeer + 2)\r\n         lngPosLeer = <span style=\"color:blue;\">InStr<\/span>(lngPosLeer + 1, strText, \" \")\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     strText = UmlauteErsetzen(strText)\r\n     Me!txtName = \"cmd\" & strText\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Ereignisprozedur, die beim &Auml;ndern der Beschriftung ausgel&ouml;st wird<\/span><\/b><\/p>\n<p>Die Prozedur erfasst zun&auml;chst den aktuellen Text im Textfeld, und zwar &uuml;ber die Eigenschaft <b>Text<\/b>. Diese unterscheidet sich vom &uuml;blicherweise abgefragten Wert des Textfeldes, weil der Wert oder die Eigenschaft Value immer den zuletzt best&auml;tigten Wert liefert. <b>Text <\/b>hingegen liefert den aktuell angezeigten Text. Der Text landet in der Variablen <b>strText<\/b>, den wir danach mit der <b>Trim<\/b>-Funktion von f&uuml;hrenden und folgenden Leerzeichen befreien. Dann tragen wir den aktuellen Wert von <b>strText <\/b>in die Variable <b>strBeschriftung <\/b>ein, die wir sp&auml;ter in weiteren Prozeduren abfragen. Au&szlig;erdem landet die Beschriftung aus <b>strText <\/b>in der Eigenschaft <b>Caption <\/b>der Beispielschaltfl&auml;che <b>cmdBeispiel<\/b>, damit der Text direkt angezeigt wird.<\/p>\n<h2>CamelCase f&uuml;r den Schaltfl&auml;chennamen<\/h2>\n<p>Danach folgen die Schritte, in denen wir den Namen f&uuml;r die Schaltfl&auml;che aus dem aktuellen Text f&uuml;r die Beschreibung ableiten. Der Schaltfl&auml;chenname soll aus dem Pr&auml;fix <b>cmd <\/b>plus der Beschriftung bestehen, wobei wir aus der Beschriftung die Leerzeichen entfernen, neue W&ouml;rter in der CamelCase-Notation schreiben und Umlaute in die entsprechenden Vokale umwandeln. Aus <b>Jetzt l&ouml;schen <\/b>wird also der Schaltfl&auml;chenname <b>cmdJetztLoeschen<\/b>.<\/p>\n<p>Dazu ermitteln wir zuerst die Position des ersten Leerzeichens und speichern diese in der Variablen <b>lngPosLeer<\/b>. Ist diese nicht <b>0<\/b>, kommt also mindestens ein Leerzeichen in der Beschriftung vor, steigen wir in eine <b>Do While<\/b>-Schleife ein.<\/p>\n<p>Diese stellt den Wert in <b>strText <\/b>neu zusammen, und zwar aus den Zeichen bis zum ersten Leerzeichen (<b>Left(strText, lngPosLeer &#8211; 1)<\/b>), dem ersten Buchstaben des Wortes nach dem Leerzeichen als Gro&szlig;buchstaben (<b>UCase(Mid(strText, lngPosLeer + 1, 1))<\/b>) sowie dem Rest des Textes nach diesem Buchstaben (<b>Mid(strText, lngPosLeer + 2)<\/b>).<\/p>\n<p>Aus <b>Jetzt alles schlie&szlig;en <\/b>wird dann <b>JetztAlles schlie&szlig;en<\/b>. Danach pr&uuml;fen wir innerhalb der <b>Do While<\/b>-Schleife, ob es noch ein Leerzeichen im Ausdruck gibt. Das ist bei unserem Beispiel der Fall, also ist <b>lngPosLeer <\/b>noch nicht <b>0 <\/b>und wir durchlaufen die <b>Do While<\/b>-Schleife ein zweites Mal. Danach hat <b>strText <\/b>den Inhalt <b>JetztAllesSchlie&szlig;en<\/b>. <\/p>\n<p>Damit verl&auml;sst die Prozedur die Schleife und ruft die Funktion <b>UmlauteErsetzen <\/b>auf, die wie folgt aussieht:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>UmlauteErsetzen(ByVal strText<span style=\"color:blue;\"> As String<\/span>) <span style=\"color:blue;\"> As String<\/span>\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&auml;\", \"ae\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&ouml;\", \"oe\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&uuml;\", \"ue\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&Auml;\", \"Ae\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&Ouml;\", \"Oe\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&Uuml;\", \"Ue\")\r\n     strText = <span style=\"color:blue;\">Replace<\/span>(strText, \"&szlig;\", \"ss\")\r\n     UmlauteErsetzen = strText\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Die Funktion ersetzt alle Umlaute durch Vokale und <b>&szlig; <\/b>durch <b>ss<\/b>, was in unserem Beispiel zum Ergebnis <b>JetztAllesSchliessen <\/b>f&uuml;hrt. Dem stellt die Ereignisprozedur noch das Pr&auml;fix <b>cmd <\/b>voran: <b>cmdJetztAlles-Schliessen<\/b>. Schlie&szlig;lich wird die Prozedur <b>GroesseOptimieren <\/b>aufgerufen, welche die Gr&ouml;&szlig;e der Beispielschaltfl&auml;che anpasst.<\/p>\n<p>Die Prozedur <b>GroesseOptimieren <\/b>schauen wir uns weiter unten an, da diese noch weitere Steuerelemente ber&uuml;cksichtigt, die wir noch nicht erstellt haben. In Bild 3 sehen Sie einen Zwischenstand.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_003.png\" alt=\"Zwischenergebnis nach der Eingabe der Beschriftung\" width=\"549,559\" height=\"231,8849\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Zwischenergebnis nach der Eingabe der Beschriftung<\/span><\/b><\/p>\n<h2>Namen der Schaltfl&auml;che &auml;ndern<\/h2>\n<p>Wenn Sie den nun automatisch aus der Beschriftung der Schaltfl&auml;che abgeleiteten Namen &auml;ndern m&ouml;chten, k&ouml;nnen Sie dies problemlos tun. Beachten Sie nur, dass dieser bei erneuter &Auml;nderung der Beschriftung wieder von der Beschriftung abgeleitet wird. Sie k&ouml;nnen bei Bedarf eine Option einbauen, welche die nachtr&auml;gliche &Auml;nderung des Namens verhindert, wenn dieser einmal festgelegt wurde. Wir wollen es an dieser Stelle allerdings nicht zu kompliziert machen.<\/p>\n<h2>Bild ausw&auml;hlen<\/h2>\n<p>Bei der Bereitstellung der Bilder wollen wir eine eingebaute Funktion von Access nutzen. Dabei k&ouml;nnen Sie in der Entwurfsansicht eines Formulars den Ribbon-Befehl <b>Entwurf|Steuerelemente|Bild einf&uuml;gen|Durchsuchen&#8230;<\/b> nutzen, um Bilder zur Datenbank hinzuzuf&uuml;gen (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_004.png\" alt=\"Ausw&auml;hlen von Bildern f&uuml;r die aktuelle Datenbank\" width=\"649,559\" height=\"234,7703\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Ausw&auml;hlen von Bildern f&uuml;r die aktuelle Datenbank<\/span><\/b><\/p>\n<p>Diese k&ouml;nnen wir beim Programmieren der <b>.accda<\/b>-Datenbank zun&auml;chst nutzen, um ein paar als Icon zu verwendende Bilddateien in der Datenbank zu speichern. Die Bilder landen dann in einem Anlagefeld in der Tabelle <b>MSysResources<\/b>.<\/p>\n<p>Diese Tabelle verwenden wir in der Abfrage f&uuml;r die Datensatzherkunft des Kombinationsfeldes <b>cboBilder <\/b>als Datenquelle. Und wir setzen noch einen drauf, denn wir wollen auch einen Eintrag mit dem Text <b><Kein Bild> <\/b>anzeigen. Daher ben&ouml;tigen wir eine <b>UNION<\/b>-Abfrage, deren SQL-Anweisung wie folgt aussieht:<\/p>\n<pre>SELECT 0 AS ID, \"&lt;Kein Bild&gt;\" AS Name, \"\" AS Type FROM MSysResources UNION SELECT Id, Name, Type FROM MSysResources WHERE Type=\"img\"<\/pre>\n<p>Dies liefert ein Ergebnis wie in Bild 5.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_005.png\" alt=\"Datensatzherkunft f&uuml;r das Kombinationsfeld cboBilder\" width=\"424,5589\" height=\"192,5325\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Datensatzherkunft f&uuml;r das Kombinationsfeld cboBilder<\/span><\/b><\/p>\n<p>F&uuml;r das Kombinationsfeld <b>cboBilder <\/b>stellen wir die Eigenschaften <b>Spaltenanzahl <\/b>auf <b>2 <\/b>und <b>Spaltenbreiten <\/b>auf <b>0cm <\/b>ein. Danach k&ouml;nnen Sie mit dem Kombinationsfeld die Bilder wie in Bild 6 ausw&auml;hlen. Das funktioniert f&uuml;r den Moment, sp&auml;ter werden wir hier noch nachjustieren m&uuml;ssen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_006.png\" alt=\"Auswahl von Bildern mit dem Kombinationsfeld cboBilder\" width=\"549,559\" height=\"171,0107\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Auswahl von Bildern mit dem Kombinationsfeld cboBilder<\/span><\/b><\/p>\n<p>Das Aktualisieren des Kombinationsfeldes l&ouml;st das Ereignis <b>Nach Aktualisierung <\/b>mit der folgenden Ereignisprozedur aus. Diese ruft zwei Prozeduren auf: <b>BildEinstellen<\/b>, um das neue Bild festzulegen, und die bereits oben einmal aufgerufene Prozedur <b>GroesseOptimieren<\/b>. Diese soll die Gr&ouml;&szlig;e an den ge&auml;nderten Inhalt anpassen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboBilder_AfterUpdate()\r\n     BildEinstellen\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Prozedur <b>BildEinstellen <\/b>pr&uuml;ft, ob das Kombinationsfeld <b>cboBilder <\/b>den Wert <b>0 <\/b>hat, was dem Text <b><Kein Bild> <\/b>entspricht. In diesem Fall stellt es die Eigenschaft <b>Picture <\/b>der Beispielschaltfl&auml;che auf eine leere Zeichenkette ein. In allen anderen F&auml;llen weist die Prozedur der Eigenschaft <b>Picture <\/b>den Namen des Bildes aus der Tabelle <b>MSysResources <\/b>zu, also beispielsweise <b>ok <\/b>oder <b>close<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>BildEinstellen()\r\n     <span style=\"color:blue;\">If <\/span>Me!cboBilder = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cmdBeispiel.Picture = \"\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!cmdBeispiel.Picture = Me!cboBilder.Column(1)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Hintergrund transparent schalten<\/h2>\n<p>Das Kontrollk&auml;stchen <b>chkTransparent <\/b>soll die Eigenschaft <b>BackStyle <\/b>entweder auf den Wert <b>0 <\/b>einstellen (transparent) oder auf den Wert <b>1 <\/b>(ausgef&uuml;llt).<\/p>\n<p>Dies wird direkt nach dem W&auml;hlen eines neuen Wertes auf die Beispielschaltfl&auml;che angewendet:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>chkTransparent_AfterUpdate()\r\n     <span style=\"color:blue;\">If <\/span>Me!chkTransparent<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cmdBeispiel.BackStyle = 0\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!cmdBeispiel.BackStyle = 1\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Beschriftungsanzeige einstellen<\/h2>\n<p>Das Kombinationsfeld <b>cboBeschriftungAnzeigen <\/b>erlaubt es, einen der sechs vorgesehenen Werte f&uuml;r die Eigenschaft <b>Anordnung der Bildbeschriftung <\/b>vorzunehmen. Die sechs Werte tragen wir direkt in die Eigenschaft <b>Datensatzherkunft <\/b>des Kombinationsfeldes ein:<\/p>\n<pre>\"0\";\"Keine Beschriftung\";\"1\";\"Standard\";2;\"Beschriftung oben\";3;\"Beschriftung unten\";4;\"Beschriftung links\";5;\"Beschriftung rechts\"<\/pre>\n<p>Damit nur die Texte und nicht die Zahlen angezeigt werden und die Liste &uuml;berhaupt korrekt verarbeitet wird, legen Sie die Eigenschaft <b>Herkunftstyp <\/b>auf <b>Wertliste<\/b>, <b>Spaltenanzahl <\/b>auf <b>2 <\/b>und <b>Spaltenbreiten <\/b>auf <b>0cm <\/b>fest.<\/p>\n<p>Nach der Auswahl eines der Werte wird der passende Zahlenwert der VBA-Eigenschaft <b>PictureCaptionArrangement <\/b>zugewiesen. Anschlie&szlig;end erfolgt der obligatorische Aufruf der Prozedur <b>GroesseOptimieren<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboBeschriftungAnzeigen_AfterUpdate()\r\n     Me!cmdBeispiel.PictureCaptionArrangement =  Me!cboBeschriftungAnzeigen\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Abstand zwischen Bild und Schrift einstellen<\/h2>\n<p>Wenn Sie einer Schaltfl&auml;che ein Icon und einen Text zuweisen, kann es sein, dass der Platz zwischen beiden Elementen etwas zu klein ist. Dann bietet es sich an, dem Text ein oder mehrere Leerzeichen voranzustellen. Das erledigen wir mit dem Kombinationsfeld <b>cboAbstandBildSchrift<\/b>, das die Werte <b>0;1;2;3 <\/b>als Wertliste anzeigt. Nach der Auswahl eines Wertes mit diesem Feld feuert das Ereignis <b>Nach Aktualisierung <\/b>und l&ouml;st die folgende Ereignisprozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboAbstandBildSchrift_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>strLeerzeichen<span style=\"color:blue;\"> As String<\/span>\r\n     strLeerzeichen = Space(Me!cboAbstandBildSchrift)\r\n     Me!cmdBeispiel.Caption =  strLeerzeichen & strBeschriftung\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Prozedur speichert eine Zeichenkette mit der dem Zahlenwert entsprechen Menge Leerzeichen in der Variablen <b>strLeerzeichen<\/b>. Dann f&uuml;gt sie diese vor der Beschriftung aus <b>strBeschriftung <\/b>ein und weist das Ergebnis der Eigenschaft <b>Caption <\/b>der Beispielschaltfl&auml;che zu. Schlie&szlig;lich ruft auch diese Prozedur die Routine <b>GroesseOptimieren <\/b>auf.<\/p>\n<h2>Bildgr&ouml;&szlig;e eingeben<\/h2>\n<p>Wir k&ouml;nnten theoretisch die zu verwendenden Bilder analysieren und die Gr&ouml;&szlig;e per Code ermitteln. Das ist uns aber an dieser Stelle zu aufwendig, weshalb wir dem Benutzer selbst die M&ouml;glichkeit geben, die Bildabmessungen in die beiden Textfelder <b>txtBildbreite <\/b>und <b>txtBildhoehe <\/b>einzugeben.<\/p>\n<p>Die Eingabe l&ouml;st die folgenden Prozeduren aus, die jeweils die Routine <b>GroesseOptimieren <\/b>aufrufen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBildbreite_AfterUpdate()\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>txtBildhoehe_AfterUpdate()\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Fett dargestellte Beschriftung<\/h2>\n<p>Das Kontrollk&auml;stchen <b>chkFetteSchrift <\/b>gibt an, ob die Beschriftung der Schaltfl&auml;che fett angezeigt werden soll. Die &Auml;nderung des Wertes des Kontrollk&auml;stchens l&ouml;st diese Prozedur aus, die das Format der Beschriftung der Beispielschaltfl&auml;che anpasst:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>chkFetteSchrift_AfterUpdate()\r\n     Me!cmdBeispiel.FontBold = Me!chkFetteSchrift\r\n     GroesseOptimieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Ereignisprozedur ausw&auml;hlen<\/h2>\n<p>Schlie&szlig;lich wollen wir dem Benutzer noch die M&ouml;glichkeit geben, den Inhalt der Ereignisprozedur, die durch das Ereignis <b>Beim Klicken <\/b>ausgel&ouml;st wird, festzulegen. Dazu haben wir eine Tabelle vorgesehen, um verschiedene Anweisungen zu speichern.<\/p>\n<p>Diese Tabelle enth&auml;lt die Felder <b>Ereignis-prozedurID<\/b>, <b>Bezeichnung <\/b>und <b>Code <\/b>und sieht im Entwurf wie in Bild 7 aus. F&uuml;r das Feld <b>Bezeichnung <\/b>haben wir einen eindeutigen Index festgelegt, da jede Bezeichnung nur einmal vorkommen darf.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_007.png\" alt=\"Entwurf der Tabelle zum Speichern der Prozedurinhalte\" width=\"549,559\" height=\"374,1478\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Entwurf der Tabelle zum Speichern der Prozedurinhalte<\/span><\/b><\/p>\n<p>F&uuml;r das Kombinationsfeld <b>cboEreignisprozeduren <\/b>legen wir die folgende Abfrage auf Basis der Tabelle <b>tblEreignisprozeduren <\/b>als Datensatzherkunft fest:<\/p>\n<pre>SELECT 0 AS EreignisprozedurID, ''&lt;Keine Ereignisprozedur&gt;'' AS Bezeichnung FROM tblEreignisprozeduren\r\nUNION\r\nSELECT EreignisprozedurID, Bezeichnung\r\nFROM tblEreignisprozeduren\r\nORDER BY Bezeichnung;<\/pre>\n<p>Auch hier nutzen wir eine <b>UNION<\/b>-Abfrage, um einen zus&auml;tzlichen Eintrag zum Kombinationsfeld hinzuzuf&uuml;gen. Diese enth&auml;lt den Wert <b>0 <\/b>und den Text <b><Keine Ereignisprozedur><\/b>.<\/p>\n<p>Und wieder stellen wir die beiden Eigenschaften <b>Spaltenanzahl <\/b>und <b>Spaltenbreiten <\/b>auf die Werte <b>2 <\/b>und <b>0cm <\/b>ein. Wenn der Benutzer einen Eintrag im Kombinationsfeld ausw&auml;hlt, geschieht ausnahmsweise einmal nichts &#8211; die Ereignisprozedur wird erst beim Abschlie&szlig;en des Assistenten zur neu erstellten Schaltfl&auml;che hinzugef&uuml;gt.<\/p>\n<p><!--30percent--><\/p>\n<p>Mit der Schaltfl&auml;che <b>cmdEreignisprozedurenBearbeiten <\/b>soll der Benutzer ein Formular zum Verwalten der Ereignisprozeduren &ouml;ffnen k&ouml;nnen. Es l&ouml;st die Prozedur aus Listing 2 aus.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEreignisprozedurenBearbeiten_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngEreignisprozedurID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">If <\/span>Nz(Me!cboEreignisprozeduren, 0) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         DoCmd.OpenForm \"frmEreignisprozeduren\", WindowMode:=acDialog, datamode:=acFormAdd\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         DoCmd.OpenForm \"frmEreignisprozeduren\", WindowMode:=acDialog, WhereCondition:=\"EreignisprozedurID = \" _\r\n             & Me!cboEreignisprozeduren, datamode:=acFormEdit\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmEreignisprozeduren\")<span style=\"color:blue;\"> Then<\/span>\r\n         lngEreignisprozedurID = Nz(Forms!frmEreignisprozeduren!EreignisprozedurID, 0)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngEreignisprozedurID = 0<span style=\"color:blue;\"> Then<\/span>\r\n             Me!cboEreignisprozeduren = lngEreignisprozedurID\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         DoCmd.Close acForm, \"frmEreignisprozeduren\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Ereignisprozedur zum Anzeigen des Dialogs f&uuml;r die Verwaltung von Ereignisprozeduren<\/span><\/b><\/p>\n<p>Die Prozedur pr&uuml;ft zun&auml;chst, ob der Eintrag <b><Keine Ereignisprozedur> <\/b>ausgew&auml;hlt ist, also der Wert <b>0<\/b>. Falls ja, wird ein Formular namens <b>frmEreignisprozeduren <\/b>als modaler Dialog im Modus zum Hinzuf&uuml;gen eines Datensatzes ge&ouml;ffnet. Anderenfalls erfolgt das &Ouml;ffnen mit <b>DoCmd.OpenForm <\/b>im Bearbeitungsmodus und eine <b>WhereCondition <\/b>&uuml;bergibt den Prim&auml;rschl&uuml;sselwert des aktuell im Kombinationsfeld <b>cboEreignisprozeduren <\/b>gew&auml;hlten Eintrags als Kriterium an das Formular.<\/p>\n<p>In beiden F&auml;llen l&auml;uft die Prozedur durch das &Ouml;ffnen des Formulars <b>frmEreignisprozeduren<\/b> als modaler Dialog erst dann weiter, wenn das Formular geschlossen oder unsichtbar gemacht wird. Dann pr&uuml;ft die Prozedur, ob das Formular noch ge&ouml;ffnet ist. Falls ja, &uuml;bernimmt die Prozedur den aktuell im Formular angezeigten Datensatz in das Kombinationsfeld <b>cboEreignisprozeduren<\/b>. Falls kein Datensatz ausgew&auml;hlt ist, geschieht nichts. Das Formular wird dann einfach geschlossen.<\/p>\n<p>Wenn das Formular schon geschlossen ist, geht die aufrufende Prozedur davon aus, dass der Benutzer das Formular <b>frmEreignisprozeduren <\/b>mit der <b>Abbrechen<\/b>-Schaltfl&auml;che geschlossen hat. Das Kombinationsfeld wird dann ebenfalls nicht aktualisiert.<\/p>\n<h2>Ereignisprozeduren verwalten<\/h2>\n<p>Zum Verwalten der Ereignisprozeduren legen wir ein Formular namens <b>frmEreignisprozeduren <\/b>an (siehe Bild 8). Dieses binden wir an die Tabelle <b>tblEreignisprozeduren<\/b> und ziehen die beiden Felder <b>Bezeichnung <\/b>und <b>Code <\/b>in den Detailbereich der Entwurfsansicht. Au&szlig;erdem f&uuml;gen wir ein Kombinationsfeld namens <b>cboSchnellauswahl <\/b>hinzu. Dieses verwendet ebenfalls die Tabelle <b>tblEreignisprozeduren <\/b>als Basis f&uuml;r die Datensatzherkunft. In diesem Fall stellen wir eine Abfrage zusammen, welche die beiden Felder <b>EreignisprozedurID <\/b>und <b>Bezeichnung <\/b>enth&auml;lt, wobei die Eintr&auml;ge aufsteigend nach der Bezeichnung sortiert werden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_008.png\" alt=\"Entwurf des Formulars frmEreignisprozeduren\" width=\"499,5589\" height=\"284,7227\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Entwurf des Formulars frmEreignisprozeduren<\/span><\/b><\/p>\n<p>Da das Kombinationsfeld nur die Bezeichnungen der Ereignisprozeduren anzeigen soll und nicht die Prim&auml;rschl&uuml;sselwerte, stellen wir noch die Eigenschaften <b>Spaltenanzahl <\/b>auf <b>2 <\/b>und <b>Spaltenbreiten <\/b>auf <b>0cm <\/b>ein.<\/p>\n<p>Damit das Formular beim &Ouml;ffnen vom Assistenten aus mittig angezeigt wird, stellen wir die Eigenschaft <b>Automatisch zentrieren <\/b>auf den Wert <b>Ja <\/b>ein.<\/p>\n<p>Die aktuell angezeigte Ereignisprozedur soll beim Schlie&szlig;en des Formulars in das Kombinationsfeld <b>cboEreignisprozeduren <\/b>des aufrufenden Formulars &uuml;bernommen werden. Das erledigen wir in der aufrufenden Prozedur, die pr&uuml;ft, ob das Formular <b>frmEreignisprozeduren <\/b>ausgeblendet oder geschlossen wird. Dazu legen wir die beiden Schaltfl&auml;chen <b>cmdOK <\/b>und <b>cmdAbbrechen <\/b>an, welche die folgenden Ereignisprozeduren ausl&ouml;sen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdAbbrechen_Click()\r\n     DoCmd.Close acForm, Me.Name\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdOK_Click()\r\n     Me.Visible = <span style=\"color:blue;\">False<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>F&uuml;r ein wenig mehr Komfort soll das Formular <b>frmEreignis-prozeduren <\/b>ein Kombinationsfeld zur Schnellauswahl von Ereignisprozeduren anbieten.<\/p>\n<p>Dieses l&ouml;st nach der Auswahl die folgende Prozedur aus und zeigt damit die gew&auml;hlte Ereignisprozedur im Formular an:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboSchnellauswahl_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>lngEreignisprozedurID<span style=\"color:blue;\"> As Long<\/span>\r\n     lngEreignisprozedurID = Nz(Me!cboSchnellauswahl, 0)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngEreignisprozedurID = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me.Filter = \"EreignisprozedurID = \"  & Me!EreignisprozedurID\r\n         Me.FilterOn = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me.Filter = \"\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Und schlie&szlig;lich wollen wir auch noch, dass das Kombinationsfeld zur Schnellauswahl eines Datensatzes immer den Eintrag anzeigt, der auch im Formular erscheint. Das erledigen wir mit einer Prozedur, die beim Anzeigen eines Datensatzes ausgel&ouml;st wird und welche <b>cboSchnellauswahl <\/b>auf den Wert des Feldes <b>EreignisprozedurID <\/b>einstellt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     Me!cboSchnellauswahl =  Me!EreignisprozedurID\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Der Aufruf dieses Formulars sieht wie in Bild 9 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_009.png\" alt=\"Aufruf des Formulars zum Verwalten der Ereignisprozeduren\" width=\"624,559\" height=\"448,073\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Aufruf des Formulars zum Verwalten der Ereignisprozeduren<\/span><\/b><\/p>\n<h2>Initialisierung des Hauptformulars<\/h2>\n<p>Wir gehen davon aus, dass der Benutzer den Assistenten nutzt, um neue Schaltfl&auml;chen anzulegen und nicht zum Bearbeiten vorhandener Schaltfl&auml;chen. Das w&auml;re zwar auch m&ouml;glich, w&uuml;rde aber ebenfalls den Rahmen sprengen. Daher initialisieren wir das Formular beim Anzeigen mit einigen Standardwerten. Das erledigt die Prozedur Initialisieren wie folgt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Initialisieren()\r\n     Me!txtBeschriftung = \"OK\"\r\n     strBeschriftung = Me!txtBeschriftung\r\n     Me!txtName = \"cmdOK\"\r\n     Me!cboBilder = Bildnummer(\"ok\")\r\n     Me!chkTransparent = <span style=\"color:blue;\">True<\/span>\r\n     Me!cboBeschriftungAnzeigen = 1\r\n     Me!cboAbstandBildSchrift = 1\r\n     Me!txtBildbreite = 24\r\n     Me!txtBildhoehe = 24\r\n     Me!chkFetteSchrift = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">With<\/span> Me.cmdBeispiel\r\n         .Caption = Me!txtBeschriftung\r\n         .PictureCaptionArrangement =  Me!cboBeschriftungAnzeigen\r\n         BildEinstellen\r\n         GroesseOptimieren\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Sie k&ouml;nnten eine weitere Tabelle anlegen, die verschiedene Konstellationen speichert &#8211; zum Beispiel eine mit einer <b>OK<\/b>-Schaltfl&auml;che, eine mit einer <b>Abbrechen<\/b>-Schaltfl&auml;che und so weiter. Zum Einstellen des Steuerelements <b>cboBilder <\/b>nutzt die Prozedur eine Hilfsfunktion namens <b>Bildnummer<\/b> (siehe Listing 3). Dieser &uuml;bergibt sie den Namen des Bildes, in diesem Fall <b>ok<\/b>, und ermittelt den Prim&auml;rschl&uuml;sselwert f&uuml;r dieses Bild in der Tabelle <b>MSysResources<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>Bildnummer(strBild<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> db = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM MSysResources WHERE Name = ''\" & strBild & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         Bildnummer = rst!Id\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Funktion zum Ermitteln der Bildnummer aus der Tabelle MSysResources<\/span><\/b><\/p>\n<p>Dieser Wert wird schlie&szlig;lich f&uuml;r das Kombinationsfeld eingestellt.<\/p>\n<p>Die Prozedur <b>Initialisieren <\/b>wird durch die Ereignisprozedur aufgerufen, die durch das Ereignis <b>Beim Laden <\/b>ausgel&ouml;st wird:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     Initialisieren\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Optimieren der Schaltfl&auml;chengr&ouml;&szlig;e<\/h2>\n<p>Damit kommen wir zu einer der komplizierteren Aufgaben in diesem Add-In: Das automatische Ermitteln der Gr&ouml;&szlig;e f&uuml;r die Schaltfl&auml;che in Abh&auml;ngigkeit von der Anzeige eines Bildes und seiner Gr&ouml;&szlig;e, der L&auml;nge und Gr&ouml;&szlig;e des Textes und des zus&auml;tzlichen Abstands zwischen Bild und Schrift.<\/p>\n<p>Au&szlig;erdem kann es auch noch sein, dass der Benutzer Icon und Beschriftung nicht nebeneinander, sondern untereinander anordnet. All dies deckt die Prozedur <b>GroesseOptimieren <\/b>ab (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>GroesseOptimieren()\r\n     <span style=\"color:blue;\">Dim <\/span>strKompletteBeschriftung <span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strLeerzeichen<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngFett<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngBreite<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngHoehe<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngBildbreite<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngBildhoehe<span style=\"color:blue;\"> As Long<\/span>\r\n     strLeerzeichen = Space(Me!cboAbstandBildSchrift)\r\n     strKompletteBeschriftung = strLeerzeichen & strBeschriftung\r\n     <span style=\"color:blue;\">If <\/span>Me!cmdBeispiel.FontBold<span style=\"color:blue;\"> Then<\/span>\r\n         lngFett = 700\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         lngFett = 400\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     WizHook.Key = 51488399\r\n     WizHook.TwipsFromFont Me!cmdBeispiel.FontName, Me!cmdBeispiel.FontSize, lngFett, 0, 0, 0, _\r\n         strKompletteBeschriftung, 0, lngBreite, lngHoehe\r\n     <span style=\"color:blue;\">If <\/span>Me!cboBilder = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cmdBeispiel.Width = lngBreite + 100 \r\n         Me!cmdBeispiel.Height = lngHoehe + 100 \r\n     <span style=\"color:blue;\">Else<\/span>\r\n         lngBildbreite = ConvertPIXELSToTWIPS(Me!txtBildbreite, 0)\r\n         lngBildhoehe = ConvertPIXELSToTWIPS(Me!txtBildhoehe, 1)\r\n         Select Case Me!cboBeschriftungAnzeigen\r\n             <span style=\"color:blue;\">Case <\/span>acNoPictureCaption\r\n                 Me!cmdBeispiel.Width = lngBildbreite + 120\r\n                 Me!cmdBeispiel.Height = lngBildhoehe + 120\r\n             <span style=\"color:blue;\">Case <\/span>acGeneral, acLeft, acRight\r\n                 Me!cmdBeispiel.Width = lngBreite + 120 + lngBildbreite\r\n                 Me!cmdBeispiel.Height = lngBildhoehe + 120\r\n             <span style=\"color:blue;\">Case <\/span>acTop, acBottom\r\n                 Me!cmdBeispiel.Width = lngBreite + 120\r\n                 Me!cmdBeispiel.Height = lngBildhoehe + lngHoehe + 120\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Prozedur zum Optimieren der Gr&ouml;&szlig;e der Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Diese Prozedur ermittelt die zwischen Bild und Beschriftung einzuf&uuml;genden Leerzeichen mit der <b>Space<\/b>-Funktion und speichert diese in der Variablen <b>strLeerzeichen<\/b>.<\/p>\n<p>Dann f&uuml;gt sie die Leerzeichen mit der Beschriftung aus <b>strBeschriftung <\/b>zusammen und speichert das Ergebnis in der Variablen <b>strKompletteBeschriftung<\/b>.<\/p>\n<p>Danach folgt die Ermittlung eines Zahlenwertes f&uuml;r die Schriftdicke. Ist die Beschriftung der Schaltfl&auml;che fett, legen wir f&uuml;r die Variable <b>lngFett<\/b> den Wert <b>700 <\/b>fest, anderenfalls den Wert <b>400<\/b>.<\/p>\n<p>Danach folgt ein wenig WizHook-Magie: Wir verwenden eine undokumentierte Funktion namens <b>TwipsFromFont<\/b>, um zu ermitteln, welche Breite und welche H&ouml;he der Text der Schaltfl&auml;che in Anspruch nimmt. Diese Funktion muss vorher durch Einstellen der Eigenschaft <b>Key <\/b>der <b>WizHook<\/b>-Klasse auf einen bestimmten Zahlenwert aktiviert werden.Daf&uuml;r &uuml;bergeben wir einige Parameter, unter anderem die Schriftart, die Schriftgr&ouml;&szlig;e, den soeben ermittelten Wert f&uuml;r die Schriftdicke, den betreffenden Text sowie zwei Variablen namens <b>lngBreite <\/b>und <b>lngHoehe<\/b>, die von der Funktion <b>TwipsFromFont <\/b>mit den Ergebnissen gef&uuml;llt werden.<\/p>\n<p>Wenn das Kombinationsfeld <b>cboBilder <\/b>den Wert 0 enth&auml;lt, also wenn kein Bild angezeigt werden soll, ermittelt die Prozedur im <b>If<\/b>-Zweig einer <b>If&#8230;Then<\/b>-Bedingung die Breite auf Basis der Breite des Textes plus plus <b>120 <\/b>(damit ein wenig Platz zwischen Inhalt und Schaltfl&auml;chenrand verbleibt).<\/p>\n<p>Hat <b>cboBilder <\/b>einen anderen Wert als <b>0<\/b>, also soll ein Bild angezeigt werden, wird der <b>Else<\/b>-Zweig der &auml;u&szlig;eren <b>If&#8230;Then<\/b>-Bedingung durchlaufen. Hier rechnet die Prozedur mithilfe der Hilfsfunktion <b>ConvertPIXELSToTWIPS <\/b>die Breite und die H&ouml;he des Icons von den in den beiden Textfeldern <b>txtBildhoehe <\/b>und <b>txtBildbreite <\/b>angegebenen Werten in der Einheit Pixel in Twips um. Die Ergebnisse landen in den Variablen <b>lngBildbreite <\/b>und <b>lngBildhoehe<\/b>.<\/p>\n<p>In diesem Teil ist ein Bild vorhanden, also m&uuml;ssen wir noch abfragen, wie das Bild angeordnet ist. Das geschieht in der <b>Select Case<\/b>-Bedingung. Hier pr&uuml;fen wir den Wert des Kombinationsfeldes <b>cboBeschriftungAnzeigen<\/b> und verwenden Konstanten wie <b>acNoPictureCaption<\/b>, <b>acGeneral <\/b>oder <b>acLeft <\/b>als Vergleichswerte.<\/p>\n<p>Im Falle des Wertes <b>acNoPictureCaption <\/b>ist keine Beschriftung vorhanden. In diesem Fall stellen wir H&ouml;he und Breite der Schaltfl&auml;che auf die f&uuml;r die Bildh&ouml;he und Bildbreite ermittelten Werte plus <b>120 <\/b>als Rand ein.<\/p>\n<p>F&uuml;r die Werte <b>acGeneral<\/b>, <b>acLeft <\/b>und <b>acRight<\/b>, also alle Einstellungen, bei benen Bild und Beschriftung nebeneinander positioniert werden, weisen wir der Eigenschaft Width die Breite des Textes plus die Breite des Bildes plus <b>120 <\/b>zu. F&uuml;r die H&ouml;he legen wir die Bildh&ouml;he plus <b>120<\/b> fest.<\/p>\n<p>F&uuml;r die Werte <b>acTop <\/b>und <b>acBottom<\/b>, also Anordnungen, wo Bild und Beschriftungen &uuml;ber- beziehungsweise untereinander angeordnet werden, ermitteln wir die Breite aus der Breite des Textes plus <b>120 <\/b>und die H&ouml;he aus der H&ouml;he des Textes plus der H&ouml;he des Bildes plus <b>120<\/b>.<\/p>\n<h2>Anwendung Add-In-f&auml;hig machen<\/h2>\n<p>Das war der einfachere Teil: Wir haben ein Formular erstellt, dass die Anforderungen an die zu erstellende Schaltfl&auml;che aufnimmt. Nun folgen die Schritte, mit denen wir die Anwendung so umprogrammieren, dass sie auch als Steuerelement-Assistent funktioniert.<\/p>\n<p>Ab jetzt wird es insofern spannend, da sie nicht mehr direkt in der Add-In-Datenbank arbeiten, sondern diese immer wieder durch das Hinzuf&uuml;gen einer neuen Schaltfl&auml;che in einer anderen Datenbank aktivieren, Fehler oder falsche Abl&auml;ufe entdecken und diese beheben wollen. Das Beheben gelingt aber beispielsweise beim Auftreten eines Laufzeitfehlers nicht, indem Sie in den Debugging-Modus wechseln und dann direkt die notwendigen Korrekturen vornehmen.<\/p>\n<p>Das VBA-Modul des Add-Ins ist dann n&auml;mlich in einer Form ge&ouml;ffnet, dass &Auml;nderungen zwar vorgenommen, aber nicht gespeichert werden k&ouml;nnen. Wenn Sie sich also wundern, dass behobene Fehler beim n&auml;chsten Test immer wieder auftreten, dann liegt es daran.<\/p>\n<p>Sie m&uuml;ssen also zum Reparieren des Codes immer wieder die Host-Anwendung schlie&szlig;en, die Add-In-Datenbank &ouml;ffnen, die &Auml;nderungen durchf&uuml;hren und dann erneut testen.<\/p>\n<p>Eine kleine Erleichterung kann ich Ihnen ans Herz legen: Sie k&ouml;nnen im Debugging-Modus &Auml;nderungen am Code des Add-Ins durchf&uuml;hren und diesen dann auch in der ge&auml;nderten Version fortsetzen. Speichern Sie den Code des aktuellen Moduls zu diesem Zeitpunkt in der Zwischenablage, dann k&ouml;nnen Sie die &Auml;nderungen beim n&auml;chsten direkten &Ouml;ffnen des Add-Ins dort hineinkopieren.<\/p>\n<h2>Die n&auml;chsten Schritte<\/h2>\n<p>Welche Schritte sind nun noch n&ouml;tig Als Erstes m&uuml;ssen wir dem Formular beim Starten des Assistenten vermitteln, welches Steuerelement angepasst werden soll &#8211; dieses erhalten wir in der beim Start aufgerufenen Funktion <b>Autostart<\/b> mit dem ersten Parameter.<\/p>\n<p>Diesen Namen sowie den Namen des Formulars, in dem die Schaltfl&auml;che angelegt wurde, &uuml;bergeben wir beim Aufruf des Formulars <b>frmButtonWizard <\/b>per &Ouml;ffnungsargument. Wir ben&ouml;tigen den Namen sp&auml;ter, wenn der Benutzer den Schaltfl&auml;chen-Assistenten schlie&szlig;t, um das frisch angelegte Steuerelement anzupassen.<\/p>\n<p>Die <b>Autostart<\/b>-Funktion sieht nach diesen &Auml;nderungen wie in Listing 5 aus. Wir f&uuml;gen also Steuerelementname und Formularname durch das Pipe-Zeichen getrennt im &Ouml;ffnungsargument zusammen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>Autostart(strCtlName<span style=\"color:blue;\"> As String<\/span>, strObjectName<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Variant<\/span>\r\n     DoCmd.OpenForm \"frmButtonWizard\", WindowMode:=acDialog, OpenArgs:=strCtlName & \"|\" & Screen.ActiveForm.Name\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Die angepasste Funktion Autostart<\/span><\/b><\/p>\n<h2>Parameter im Formular entgegen nehmen<\/h2>\n<p>F&uuml;r den Namen der Schaltfl&auml;che und des Formulars legen wir im Klassenmodul des Formulars <b>frmButtonWizard <\/b>die folgenden beiden <b>String<\/b>-Variablen an:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>strSchaltflaeche<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>strFormular<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p>In der Ereignisprozedur, die beim &Ouml;ffnen des Formulars ausgel&ouml;st wird, lesen wir dann die beiden Informationen aus dem &Ouml;ffnungsargument aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Open(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strOpenArgs<span style=\"color:blue;\"> As String<\/span>\r\n     strOpenArgs = Nz(Me.OpenArgs, \"\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strOpenArgs) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> (\"Keine Schaltfl&auml;che angelegt.\")\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         strSchaltflaeche = <span style=\"color:blue;\">Split<\/span>(strOpenArgs, \"|\")(0)\r\n         strFormular = <span style=\"color:blue;\">Split<\/span>(strOpenArgs, \"|\")(1)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Anlegen beziehungsweise Anpassen der neuen Schaltfl&auml;che<\/h2>\n<p>Ein Klick auf die Schaltfl&auml;che <b>OK <\/b>soll die getroffenen Einstellungen f&uuml;r die neue Schaltfl&auml;che &uuml;bernehmen. Das l&ouml;st die folgende Prozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdOK_Click()\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> SchaltflaecheAnpassen<span style=\"color:blue;\"> Then<\/span>\r\n         Application.DeleteControl strFormular, Me!txtName\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Schaltfl&auml;che wurde nicht erstellt.\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         EreignisprozedurAnlegen\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     DoCmd.Close acForm, Me.Name\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese ruft die Funktion <b>SchaltflaecheAnpassen<\/b> aus Listing 6 auf. Diese Funktion referenziert mit der Variablen <b>frm <\/b>das Formular, in dem die neue Schaltfl&auml;che angelegt wurde, und mit <b>cmd <\/b>die Schaltfl&auml;che. Als Erstes pr&uuml;ft sie, ob bereits ein Steuerelement mit dem neuen Namen vorhanden ist. Dazu wird versucht, bei deaktivierter Fehlerbehandlung mit der Variablen <b>ctl <\/b>ein Steuerelement mit dem Namen aus <b>Me!txtName<\/b> zu referenzieren.<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>SchaltflaecheAnpassen()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>cmd<span style=\"color:blue;\"> As <\/span>CommandButton\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Set<\/span> frm = Forms(strFormular)\r\n     <span style=\"color:blue;\">Set<\/span> cmd = frm.Controls(strSchaltflaeche)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> ctl = frm.Controls(Me!txtName)\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> ctl Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         If <span style=\"color:blue;\">MsgBox<\/span>(\"Es ist bereits ein Steuerelement namens ''\" & Me!txtName & \"'' vorhanden. &Uuml;berschreiben\", _\r\n                 vbYesNo + vbExclamation, \"&Uuml;berschreiben\") = vbYes Then\r\n             Application.DeleteControl strFormular, Me!txtName\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Exit Function<\/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;\">With<\/span> cmd\r\n         .Caption = Me!cmdBeispiel.Caption\r\n         .Name = Me!txtName\r\n         BildKopieren Me!cmdBeispiel.Picture\r\n         .Picture = Me!cmdBeispiel.Picture\r\n         .BackStyle = Me!cmdBeispiel.BackStyle\r\n         .FontBold = Me!cmdBeispiel.FontBold\r\n         .Width = Me!cmdBeispiel.Width\r\n         .Height = Me!cmdBeispiel.Height\r\n         .PictureCaptionArrangement = Me!cmdBeispiel.PictureCaptionArrangement\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     SchaltflaecheAnpassen = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion zum Anpassen der neuen Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Ist diese Variable danach nicht gef&uuml;llt, fragt die Funktion den Benutzer, ob das vorhandene Steuerelement gel&ouml;scht werden soll. Ist das der Fall, entfernt es die Funktion mit der <b>DeleteControl<\/b>-Methode. Anderenfalls endet die Funktion hier. Ist noch kein Steuerelement diesen Namens vorhanden, beginnt das Einstellen der Eigenschaften der neu erstellten Schaltfl&auml;che. Dabei weist die Funktion in den meisten F&auml;llen einfach die Werte der Eigenschaften der Beispielschaltfl&auml;che aus dem Assistenten-Formular zu.<\/p>\n<p>Bevor wir das Bild zuweisen, m&uuml;ssen wir allerdings sicherstellen, dass die Tabelle <b>MSysResources <\/b>auch die Bilddatei enth&auml;lt, die wir zuweisen wollen. Dazu rufen wir eine Prozedur namens <b>BildKopieren <\/b>auf, die wir weiter unten besprechen. Schlie&szlig;lich stellt die Funktion den R&uuml;ckgabewert auf <b>True <\/b>ein. Die aufrufende Prozedur schlie&szlig;t anschlie&szlig;end den Schaltfl&auml;chen-Assistenten.<\/p>\n<h2>Bild von der Add-In-Datenbank in die Zieldatenbank kopieren<\/h2>\n<p>Die Prozedur <b>BildKopieren <\/b>kopiert das als Parameter angegebene Bild aus der Tabelle <b>MSysResources <\/b>der Add-In-Datenbank in die gleichnamige Tabelle der Zieldatenbank. Dabei deklariert sie gleich zwei Variablen mit dem Datentyp <b>Database<\/b> und vier mit dem Datentyp <b>Recordset<\/b> (siehe Listing 7).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>BildKopieren(strBild<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>dbAddIn<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>dbHost<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rstAddIn<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstHost<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstAddInAttachment<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstHostAttachment<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> dbAddIn = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> dbHost = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rstAddIn = dbAddIn.OpenRecordset(\"SELECT * FROM MSysResources WHERE Name = ''\" & strBild & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Set<\/span> rstHost = dbHost.OpenRecordset(\"SELECT * FROM MSysResources WHERE Name = ''\" & strBild & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rstHost.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         If <span style=\"color:blue;\">MsgBox<\/span>(\"Es ist bereits ein Bild namens ''\" & strBild & \"'' in der Zieldatei enthalten. &Uuml;berschreiben\", _\r\n                 vbYesNo + vbExclamation, \"Bild &uuml;berschreiben\") = vbYes Then\r\n             rstHost.Delete\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">Exit Sub<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     rstHost.Add<span style=\"color:blue;\">New<\/span>\r\n     rstHost!Name = rstAddIn!Name\r\n     rstHost!Type = rstAddIn!Type\r\n     rstHost!Extension = rstHost!Extension\r\n     <span style=\"color:blue;\">Set<\/span> rstAddInAttachment = rstAddIn.Fields(\"Data\").Value\r\n     <span style=\"color:blue;\">Set<\/span> rstHostAttachment = rstHost.Fields(\"Data\").Value\r\n     rstHostAttachment.Add<span style=\"color:blue;\">New<\/span>\r\n     rstHostAttachment!FileData = rstAddInAttachment!FileData\r\n     rstHostAttachment!FileName = rstAddInAttachment!FileName\r\n     rstHostAttachment.Update\r\n     rstHost.Update\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Kopieren eines Bildes aus der Add-In-Datenbank in die Zieldatenbank<\/span><\/b><\/p>\n<p>Die beiden <b>Database<\/b>-Variablen <b>dbAddIn <\/b>und <b>dbHost <\/b>referenzieren die Add-In-Datenbank (mit <b>CodeDb<\/b>) und die aufrufende Datenbank (mit <b>CurrentDb<\/b>).<\/p>\n<p>Die ersten beiden Recordsets <b>rstAddIn <\/b>und <b>rstHost <\/b>referenzieren jeweils die Tabelle <b>MSysResources <\/b>der beiden <b>Database<\/b>-Objekte. Dabei holen wir aus der Add-In-Datenbank den Datensatz mit dem entsprechenden Namen. W&auml;hrend wir hier wissen, dass dieser Datensatz vorhanden ist (wir haben ihn schlie&szlig;lich ausgew&auml;hlt), kann der Zugriff auf den Datensatz mit dem gleichen Bildnamen in der Tabelle <b>MSysResources <\/b>der Zieldatenbank das nicht voraussetzen. Also versuchen wir es einfach und pr&uuml;fen dann mit der Eigenschaft <b>EOF<\/b>, ob das <b>Recordset <\/b>einen Datensatz enth&auml;lt. Falls nicht, gut &#8211; dann f&uuml;gen wir einfach den neuen Datensatz mit dem Bild hinzu. Ist jedoch bereits ein Bild mit dem angegebenen Namen vorhanden, fragen wir den Benutzer, ob er dieses Bild &uuml;berschreiben oder beibehalten m&ouml;chte. Falls er das Bild &uuml;berschrieben m&ouml;chte, l&ouml;schen wir den Datensatz mit der <b>Delete<\/b>-Methode, anderenfalls verlassen wir die Prozedur an dieser Stelle.<\/p>\n<p>Ist der Datensatz noch nicht vorhanden oder wurde soeben gel&ouml;scht, legen wir nun einen neuen Datensatz in der Tabelle <b>MSysResources <\/b>der Zieldatenbank an und weisen den Feldern <b>Name<\/b>, <b>Type <\/b>und <b>Extension <\/b>die entsprechenden Werte zu.<\/p>\n<p>Spannend wird es beim Feld <b>Data<\/b>, denn das enth&auml;lt das Anlage-Feld. Dieses k&ouml;nnen wir nicht einfach kopieren. Hier m&uuml;ssen wir zun&auml;chst ein weiteres Recordset mit einem Verweis auf die <b>Value<\/b>-Eigenschaft des Anlagefeldes f&uuml;llen. Diese h&auml;lt wieder ein Recordset bereit, das seinerseits unter anderem das Feld <b>FileData <\/b>mit der eigentlichen Datei enth&auml;lt.<\/p>\n<p>Also referenzieren wir das Anlage-Recordset in der Quelltabelle mit <b>rstAddInAttachment <\/b>und das in der Zieltabelle mit <b>rstHostAttachment<\/b>. Dann f&uuml;gen wir mit <b>AddNew <\/b>einen neuen Datensatz in <b>rsthostAttachment <\/b>ein und kopieren dann die Inhalte der Felder <b>FileData <\/b>und <b>FileName<\/b>. Schlie&szlig;lich aktualisieren wir die neu angelegten Datens&auml;tze in <b>rstHostAttachment <\/b>und <b>rstHost <\/b>mit der <b>Update<\/b>-Methode.<\/p>\n<h2>Anlegen abbrechen<\/h2>\n<p>Wenn Sie den Assistenten beenden wollen und die neue Schaltfl&auml;che nicht angelegt werden soll, k&ouml;nnen Sie diesen einfach mit der <b>Abbrechen<\/b>-Schaltfl&auml;che beenden. Das sieht dann wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdAbbrechen_Click()\r\n     DoCmd.Close acForm, Me.Name\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Ereignisprozedur anlegen<\/h2>\n<p>Das war es fast. Es fehlt nur noch die jeweilige Ereignisprozedur mit den daf&uuml;r ausgew&auml;hlten Anweisungen. Um diese anzulegen, ben&ouml;tigen wir im VBA-Projekt der Add-In-Datenbank noch einen neuen Verweis auf die Bibliothek <b>Microsoft Visual Basic for Applications Extensibility 5.3 Object Library<\/b>, den Sie &uuml;ber den <b>Verweise<\/b>-Dialog hinzuf&uuml;gen (Men&uuml;eintrag <b>Extras|Verweise<\/b>, siehe Bild 10). Den Aufruf der Prozedur <b>EreignisHinzufuegen <\/b>finden Sie in der weiter oben bereits vorgestellten Prozedur <b>cmdOK_Click<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_03\/pic_1309_010.png\" alt=\"Verweis auf die VBE-Bibliothek\" width=\"474,5589\" height=\"374,1123\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Verweis auf die VBE-Bibliothek<\/span><\/b><\/p>\n<h2>Prozedur zum Anlegen der Ereignisprozedur<\/h2>\n<p>Die Prozedur <b>EreignisprozedurAnlegen <\/b>sieht wie in Listing 8 aus. Sie verwendet einige Objekte der Bibliothek, die wir soeben referenziert haben. Allerdings setzt sie den ersten Objektverweis f&uuml;r die Variable <b>frm <\/b>auf das Formular, in dem wir die neue Schaltfl&auml;che angelegen. Dann pr&uuml;fen wir zuerst, ob das Formular bereits ein Klassenmodul hat. Das erledigen wir mit der Eigenschaft <b>HasModule<\/b>. Hat diese den Wert <b>False<\/b>, stellen wir ihn auf <b>True <\/b>ein, was direkt das Klassenmodul hinzuf&uuml;gt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>EreignisprozedurAnlegen()\r\n     <span style=\"color:blue;\">Dim <\/span>objVBProject<span style=\"color:blue;\"> As <\/span>VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBComponent<span style=\"color:blue;\"> As <\/span>VBComponent\r\n     <span style=\"color:blue;\">Dim <\/span>objModule<span style=\"color:blue;\"> As <\/span>CodeModule\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>cmd<span style=\"color:blue;\"> As <\/span>CommandButton\r\n     <span style=\"color:blue;\">Dim <\/span>lngEventProc<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strCode<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> frm = Forms(strFormular)\r\n     <span style=\"color:blue;\">If <\/span>frm.HasModule = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         frm.HasModule = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> cmd = frm.Controls(Me!txtName)\r\n     cmd.OnClick = \"[Event Procedure]\"\r\n     <span style=\"color:blue;\">Set<\/span> objVBProject = GetCurrentVBProject\r\n     <span style=\"color:blue;\">Set<\/span> objVBComponent = objVBProject.VBComponents(\"Form_\" & frm.Name)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> ExistsProc(Me!txtName & \"_Click\", objVBComponent)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> objModule = objVBComponent.CodeModule\r\n         lngEventProc = objModule.CreateEventProc(\"Click\", Me!txtName)\r\n         lngEventProc = lngEventProc + 1\r\n         strCode = CodeDb.OpenRecordset(\" SELECT Code FROM tblEreignisprozeduren WHERE EreignisprozedurID = \" _\r\n             & Me!cboEreignisprozeduren, dbOpenDynaset).Fields(0)\r\n         objModule.DeleteLines lngEventProc, 1\r\n         objModule.InsertLines lngEventProc, strCode\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Anlegen der Ereignisprozedur f&uuml;r die Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Dann referenzieren wir mit der Variablen <b>cmd <\/b>die neue Schaltfl&auml;che und stellen seine Eigenschaft <b>OnClick <\/b>auf <b>[Event Procedure] <\/b>ein, was gleichbedeutend ist mit dem Festlegen des Wertes <b>[Ereignisprozedur] <\/b>f&uuml;r die Eigenschaft <b>Beim Klicken <\/b>des Steuerelements.<\/p>\n<p>Nun referenzieren wir das <b>VBProject<\/b>-Element f&uuml;r das VBA-Projekt der Datenbank, in dem wir die neue Schaltfl&auml;che anlegen wollen. Das ist nicht ganz trivial, denn w&auml;hrend ein Add-In verwendet wird, enth&auml;lt der VBA-Editor mindestens zwei VBA-Projekte.<\/p>\n<p>Wir ermitteln das richtige Projekt mit der Funktion <b>GetCurrentVBProject<\/b>, die wir gleich im Anschluss beschreiben.<\/p>\n<p>Aus diesem Projekt referenzieren wir anschlie&szlig;end die VBA-Komponente mit dem aus <b>Form_ <\/b>und dem Formularnamen zusammengesetzten Namen. Hier pr&uuml;fen wir dann, ob es bereits eine Prozedur mit dem aus dem Namen der Schaltfl&auml;che und <b>_Click <\/b>zusammengesetzten Namen gibt. Dazu nutzen wir die Funktion <b>ExistsProc <\/b>&#8211; siehe ebenfalls weiter unten. Gibt es die Prozedur noch nicht, legen wir diese an.<\/p>\n<p>Dazu referenziert die Prozedur das <b>CodeModule<\/b>-Objekt von <b>objVBComponent <\/b>mit <b>objModule<\/b>. Hier legen wir mit der Methode <b>CreateEventProc <\/b>eine Ereignisprozedur f&uuml;r das Ereignis <b>Click <\/b>und die Schaltfl&auml;che mit dem Namen aus <b>txtName<\/b> an.<\/p>\n<p>Die Funktion <b>CreateEventProc <\/b>liefert die Zeilennummer der ersten Zeile der neu erstellten Methode als Ergebnis zur&uuml;ck. Damit k&ouml;nnen wir nun den f&uuml;r diese Schaltfl&auml;che vorgesehenen Code aus der Tabelle <b>tblEreignisprozeduren <\/b>zwischen die <b>Private Sub<\/b>&#8211; und die <b>End Sub<\/b>-Zeilen einf&uuml;gen.<\/p>\n<p>Den Code k&ouml;nnen wir nicht so einfach mit der <b>DLookup<\/b>-Funktion ermitteln, da diese auf die Tabellen der Datenbank zugreift, in der wir die neue Schaltfl&auml;che anlegen wollen. Wir m&uuml;ssen mit <b>OpenRecordset <\/b>&uuml;ber die mit <b>CodeDb <\/b>ermittelte Datenbank arbeiten, was aber noch nicht einmal eine zus&auml;tzliche Codezeile bedeutet.<\/p>\n<p>Die bisher einzige leere Zeile der Prozedur l&ouml;schen wir und ersetzen diese durch den Inhalt des entsprechenden Datensatzes der Tabelle <b>tblEreignisprozeduren<\/b>.<\/p>\n<p>Damit ist das Erstellen abgeschlossen und wir k&ouml;nnen uns noch die beiden Hilfsfunktionen f&uuml;r den Zugriff auf den VBA-Code ansehen.<\/p>\n<h2>Pr&uuml;fen, ob eine Prozedur bereits existiert<\/h2>\n<p>Die Funktion <b>ExistsProc <\/b>erwartet den Namen der zu untersuchenden Prozedur sowie das <b>VBComponent<\/b>-Element als Parameter (siehe Listing 9). Sie referenziert das <b>CodeModule<\/b>-Element und fragt mit der Funktion <b>ProcBodyLine <\/b>die Zeile ab, in der die mit <b>strProcname <\/b>&uuml;bergebene Funktion beginnt.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ExistsProc(strProcname<span style=\"color:blue;\"> As String<\/span>, objVBComponent<span style=\"color:blue;\"> As <\/span>VBComponent)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>objCodemodule<span style=\"color:blue;\"> As <\/span>CodeModule\r\n     <span style=\"color:blue;\">Dim <\/span>lngLine<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objCodemodule = objVBComponent.CodeModule\r\n     <span style=\"color:blue;\">With<\/span> objCodemodule\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         lngLine = .ProcBodyLine(strProcname, vbext_pk_Proc)\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngLine = 0<span style=\"color:blue;\"> Then<\/span>\r\n             ExistsProc = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Pr&uuml;fen, ob eine Prozedur bereits vorhanden ist<\/span><\/b><\/p>\n<p>Wenn die Prozedur nicht vorhanden ist, l&ouml;st diese Zeile allerdings einen Fehler aus. Deshalb haben wir die Fehlerbehandlung vorher ausgeschaltet. Hat die Variable <b>lngLine<\/b>, die eigentlich die Position der gesuchten Prozedur enthalten sollte, danach den Wert <b>0<\/b>, ist die Prozedur nicht vorhanden. Der R&uuml;ckgabewert wird nur auf <b>True <\/b>eingestellt, wenn <b>lngLine <\/b>einen anderen Wert als <b>0 <\/b>aufweist.<\/p>\n<h2>VB-Projekt der aktuellen Datenbank holen<\/h2>\n<p>Die Funktion <b>GetCurrentVBProject <\/b>soll einen Verweis auf das <b>VBProject<\/b>-Objekt des aktuellen VBA-Projekts holen. Dazu durchl&auml;uft sie alle Elemente der Auflistung <b>VBProjects<\/b>, bis es ein <b>VBProject<\/b>-Objekt findet, dessen Dateiname mit dem der mit <b>CurrentDb <\/b>ermittelten Datenbank &uuml;bereinstimmt. Der resultierende Verweis wird als Funktionswert an die aufrufende Funktion zur&uuml;ckgegeben:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetCurrentVBProject()<span style=\"color:blue;\"> As <\/span>VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBProject<span style=\"color:blue;\"> As <\/span>VBProject\r\n     <span style=\"color:blue;\">Dim <\/span>objVBComponent<span style=\"color:blue;\"> As <\/span>VBComponent\r\n     For Each objVBProject In VBE.VBProjects\r\n         <span style=\"color:blue;\">If <\/span>(objVBProject.FileName = CurrentDb.Name)<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Set<\/span> GetCurrentVBProject = objVBProject\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> objVBProject\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit diesem Add-In k&ouml;nnen Sie leicht h&uuml;bsche Schaltfl&auml;chen zu Ihren Formularen hinzuf&uuml;gen und sparen sich damit einige Handgriffe. Mit der Zeit werden Sie vielleicht feststellen, dass Sie gern mehr Schaltfl&auml;chen mit diesem Add-In verwalten wollen &#8211; dann k&ouml;nnen Sie dem Add-In eine Art Konfigurationstabelle hinzuf&uuml;gen, mit der Sie die Konfiguration einzelner Schaltfl&auml;chen speichern und wiederherstellen k&ouml;nnen.<\/p>\n<p>Eine zus&auml;tzliche Erweiterung w&auml;re die automatische Berechnung der Bildgr&ouml;&szlig;e. Au&szlig;erdem gibt es noch einige Eigenschaften, die wir nicht ber&uuml;cksichtigt haben &#8211; die Schriftart, die Hintergrundfarbe und so weiter. Diese Eigenschaftszuweisungen k&ouml;nnten Sie auch noch ber&uuml;cksichtigen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>amvButtonWizard.accda<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/54C345EF-37CD-4B76-A429-DF8FC601F4DF\/aiu_1309.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Beitrag Schaltfl&auml;chen-Assistent (www.access-im-unternehmen.de\/1308) zeigen wir, wie Sie das Grundger&uuml;st eines Schaltfl&auml;chen-Assistenten definieren. Was Sie mit dem Schaltfl&auml;chen-Assistenten anfangen k&ouml;nnen, zeigen wir Ihnen im vorliegenden Beitrag. Wir wollen zun&auml;chst das Anlegen bestimmter Standardschaltfl&auml;chen erlauben. Die erste sind einfache OK- und Abbrechen-Schaltfl&auml;chen. Diese Aufgabe kostet in jedem Formular, das sie neu erstellen, ein paar Minuten. Zeit, die Sie sich sparen k&ouml;nnen &#8211; indem Sie einmalig Zeit in die Entwicklung eines passenden Steuerelement-Assistenten investieren.<\/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":[662021,66032021,44000027],"tags":[],"class_list":["post-55001309","post","type-post","status-publish","format-standard","hentry","category-662021","category-66032021","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Schaltfl&auml;chen per Code anlegen - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Schaltfl&auml;chen per Code anlegen\" \/>\n<meta property=\"og:description\" content=\"Im Beitrag Schaltfl&auml;chen-Assistent (www.access-im-unternehmen.de\/1308) zeigen wir, wie Sie das Grundger&uuml;st eines Schaltfl&auml;chen-Assistenten definieren. Was Sie mit dem Schaltfl&auml;chen-Assistenten anfangen k&ouml;nnen, zeigen wir Ihnen im vorliegenden Beitrag. Wir wollen zun&auml;chst das Anlegen bestimmter Standardschaltfl&auml;chen erlauben. Die erste sind einfache OK- und Abbrechen-Schaltfl&auml;chen. Diese Aufgabe kostet in jedem Formular, das sie neu erstellen, ein paar Minuten. Zeit, die Sie sich sparen k&ouml;nnen - indem Sie einmalig Zeit in die Entwicklung eines passenden Steuerelement-Assistenten investieren.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-31T10:14:37+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"33\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Schaltfl&auml;chen per Code anlegen\",\"datePublished\":\"2021-07-31T10:14:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/\"},\"wordCount\":5416,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/211b269206d04b4bb2cbe1480ee96270\",\"articleSection\":[\"2021\",\"3\\\/2021\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/\",\"name\":\"Schaltfl&auml;chen per Code anlegen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/211b269206d04b4bb2cbe1480ee96270\",\"datePublished\":\"2021-07-31T10:14:37+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/211b269206d04b4bb2cbe1480ee96270\",\"contentUrl\":\"http:\\\/\\\/vg07.met.vgwort.de\\\/na\\\/211b269206d04b4bb2cbe1480ee96270\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Schaltflaechen_per_Code_anlegen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Schaltfl&auml;chen per Code anlegen\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Schaltfl&auml;chen per Code anlegen - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/","og_locale":"de_DE","og_type":"article","og_title":"Schaltfl&auml;chen per Code anlegen","og_description":"Im Beitrag Schaltfl&auml;chen-Assistent (www.access-im-unternehmen.de\/1308) zeigen wir, wie Sie das Grundger&uuml;st eines Schaltfl&auml;chen-Assistenten definieren. Was Sie mit dem Schaltfl&auml;chen-Assistenten anfangen k&ouml;nnen, zeigen wir Ihnen im vorliegenden Beitrag. Wir wollen zun&auml;chst das Anlegen bestimmter Standardschaltfl&auml;chen erlauben. Die erste sind einfache OK- und Abbrechen-Schaltfl&auml;chen. Diese Aufgabe kostet in jedem Formular, das sie neu erstellen, ein paar Minuten. Zeit, die Sie sich sparen k&ouml;nnen - indem Sie einmalig Zeit in die Entwicklung eines passenden Steuerelement-Assistenten investieren.","og_url":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/","og_site_name":"Access im Unternehmen","article_published_time":"2021-07-31T10:14:37+00:00","og_image":[{"url":"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"33\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Schaltfl&auml;chen per Code anlegen","datePublished":"2021-07-31T10:14:37+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/"},"wordCount":5416,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270","articleSection":["2021","3\/2021","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/","url":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/","name":"Schaltfl&auml;chen per Code anlegen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270","datePublished":"2021-07-31T10:14:37+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#primaryimage","url":"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270","contentUrl":"http:\/\/vg07.met.vgwort.de\/na\/211b269206d04b4bb2cbe1480ee96270"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Schaltflaechen_per_Code_anlegen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Schaltfl&auml;chen per Code anlegen"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001309","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001309"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001309\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001309"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001309"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001309"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}