{"id":55001490,"date":"2024-04-01T00:00:00","date_gmt":"2024-02-29T18:51:14","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1490"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Detailformular_per_Mausklick_erstellen","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Detailformular_per_Mausklick_erstellen\/","title":{"rendered":"Detailformular per Mausklick erstellen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Bei der Arbeit mit Microsoft Access gibt es immer wiederkehrende Aufgaben &#8211; zum Beispiel das Anlegen von Detailformularen. Diese sollen die Daten aus einfachen Tabellen darstellen und zwei Schaltfl&auml;chen namens OK und Abbrechen bereitstellen. So kann der Benutzer neue oder ge&auml;nderte Datens&auml;tze &uuml;bernehmen oder diese verwerfen. Dazu sind immer wieder viele kleine Handgriffe n&ouml;tig. Damit dies ab jetzt schneller geht, schauen wir uns an, wie wir die meisten der Schritte automatisieren k&ouml;nnen. Dazu bauen wir ein Formular, mit dem wir alle Konfigurationsschritte erledigen k&ouml;nnen &#8211; von der Auswahl der Datenquelle &uuml;ber die Benennung des Formulars bis hin zur Erstellung des vollst&auml;ndigen Formulars inklusive Code.<\/b><\/p>\n<p>Viele Formulare sind eigentlich immer gleich aufgebaut. F&uuml;r die herk&ouml;mmliche Bearbeitung von Daten ben&ouml;tigt man ein Detailformular, das die Felder eines Datensatzes anzeigt und zwei Schaltfl&auml;chen bietet, mit denen der Benutzer die eingegebenen Daten &uuml;bernehmen oder verwerfen kann. <\/p>\n<p>Im Artikel <b>Tabellendaten mit &Uuml;bersicht und Details anzeigen <\/b>(<b>www.access-im-unternehmen.de\/1488<\/b>) zeigen wir, welche Handgriffe alle n&ouml;tig sind, um ein solches Formular manuell zu erstellen.<\/p>\n<p>Im vorliegenden Beitrag stellen wir eine L&ouml;sung vor, mit der wir die Daten aus beliebigen Tabellen schnell in ein Formular umwandeln k&ouml;nnen.<\/p>\n<p>Ein Beispiel f&uuml;r eine Tabelle, auf deren Basis wir ein Formular erstellen wollen, sehen wir in Bild 1.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_001.png\" alt=\"Beispieltabelle tblMitglieder\" width=\"699,559\" height=\"271,187\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Beispieltabelle tblMitglieder<\/span><\/b><\/p>\n<p>Formulare und Tabellen zur Steuerung der Erstellung der Formulare<\/p>\n<p>Wir w&auml;ren nicht in Access, wenn wir nicht auch f&uuml;r das Erstellen von Formularen per Code die dazu ben&ouml;tigten Daten f&uuml;r die Konfiguration in Tabellen speichern und die Konfiguration in Formularen bearbeiten w&uuml;rden.<\/p>\n<p>Aber welche Daten m&uuml;ssen wir hier &uuml;berhaupt erfassen?<\/p>\n<ul>\n<li>Die wichtigste Information ist: Aus welcher Tabelle sollen die Daten &uuml;berhaupt stammen?<\/li>\n<li>Wie soll das zu erstellende Formular hei&szlig;en?<\/li>\n<li>Sollen Navigationsschaltfl&auml;chen, Datensatzmarkierer oder Bildlaufleisten angezeigt werden &#8211; und soll einer oder mehrere Datens&auml;tze angesteuert werden k&ouml;nnen?<\/li>\n<li>Welche Felder der Tabelle sollen im Detailformular angezeigt werden? Und in welcher Reihenfolge und Anordnung? Welche Breite sollen die Felder aufweisen?<\/li>\n<li>Wie sollen die Schaltfl&auml;chen <b>OK <\/b>und <b>Abbrechen <\/b>aussehen und welche Funktionen sollen sie ausl&ouml;sen? Sollen sie Icons anzeigen?<\/li>\n<\/ul>\n<p>Allein die Einstellung dieser Eigenschaften erfordert ein technisch anspruchsvolles Formular. Aber zuerst schauen wir uns an, welche Tabellen wir zum Erfassen dieser Daten ben&ouml;tigen.<\/p>\n<h2>Vorbereitungen im Datenmodell<\/h2>\n<p>Damit wir m&ouml;glichst nah am Endergebnis arbeiten k&ouml;nnen, m&uuml;ssen wir bereits im Tabellenentwurf ein wenig Vorarbeit leisten. Wenn ein Feldname nicht dem Text entspricht, der nachher als Beschriftung in der Datenblattansicht und im Detailformular verwendet werden soll, m&uuml;ssen wir den gew&uuml;nschten Text f&uuml;r die Eigenschaft <b>Beschriftung <\/b>f&uuml;r die jeweiligen Felder im Tabellenentwurf eintragen. Au&szlig;erdem wollen wir f&uuml;r Fremdschl&uuml;sselfelder, auf deren Basis Datens&auml;tze aus anderen Tabellen ausgew&auml;hlt werden sollen, direkt Nachschlagfelder definieren. Die damit festgelegten Eigenschaften k&ouml;nnen wir dann direkt in das zu erstellende Formular &uuml;bernehmen, genau wie das auch beim Hinzuf&uuml;gen von Feldern aus der Feldliste in manuell erstellten Formularen gelingt.<\/p>\n<h2>Das Konfigurationsformular im &Uuml;berblick<\/h2>\n<p>Das von uns zum Erstellen von Detailformularen verwendete Formular sehen Sie in Bild 2. Es bietet die M&ouml;glichkeit, verschiedene Konfigurationen zu speichern &#8211; wir k&ouml;nnen also Formulare auf Basis unterschiedlicher Tabellen oder Abfragen definieren und diese immer wieder neu erstellen. Das Formular erlaubt die Eingabe des Namens des zu erstellenden Detailformulars, die Auswahl der Datensatzquelle, also einer Tabelle oder Abfrage, das Festlegen eines Formulartitels und die Angabe eines einheitlichen Abstandes. Dieser wird angewendet f&uuml;r den Abstand aller Steuerelemente von den Formularr&auml;ndern und f&uuml;r den Abstand zwischen den Steuerelementen. Die Eigenschaft <b>Anzahl Spalten <\/b>haben wir vorerst nur vorbereitet, sie erf&uuml;llt noch keinen Zweck.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_002.png\" alt=\"Formular zum Konfigurieren neuer Detailformulare\" width=\"700\" height=\"515,8287\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Formular zum Konfigurieren neuer Detailformulare<\/span><\/b><\/p>\n<p>Rechts sehen wir einige typische Formulareigenschaften wie <b>Automatisch zentrieren<\/b>, <b>Datensatzmarkierer<\/b>, <b>Navigationsschaltfl&auml;chen<\/b>, <b>Bildlaufleisten <\/b>oder <b>Zyklus<\/b>.<\/p>\n<p>Darunter sehen wir zwei Bereiche, in denen wir die Eigenschaften f&uuml;r die beiden Schaltfl&auml;chen <b>OK <\/b>und <b>Abbrechen <\/b>einstellen k&ouml;nnen. Hier geben wir an, ob die jeweilige Schaltfl&auml;che &uuml;berhaupt angelegt werden soll. Dann legen wir fest, welchen Text diese anzeigen und welchen Code sie ausf&uuml;hren sollen. Schlie&szlig;lich k&ouml;nnen wir auch noch ein Icon ausw&auml;hlen und festlegen, ob die Funktion der <b>OK<\/b>-Schaltfl&auml;che auch durch die Eingabetaste ausgel&ouml;st werden soll und die Funktion der <b>Abbrechen<\/b>-Schaltfl&auml;che durch die <b>Escape<\/b>-Taste.<\/p>\n<p>Darunter sehen wir die M&ouml;glichkeit, einen Button-Style auszuw&auml;hlen. Ein Klick auf die Schaltfl&auml;che rechts daneben zeigt den Dialog aus Bild 3 an. Hier k&ouml;nnen wir einige grundlegende Einstellungen f&uuml;r das Aussehen von Schaltfl&auml;chen vornehmen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_003.png\" alt=\"Formular zum Einstellen einiger Schaltfl&auml;cheneigenschaften\" width=\"424,5589\" height=\"192,8205\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Formular zum Einstellen einiger Schaltfl&auml;cheneigenschaften<\/span><\/b><\/p>\n<p>Die Einstellung der Schriftarten haben wir ein wenig rudiment&auml;rer gestaltet. Ein Klick auf die Schaltfl&auml;che <b>Schrifteigenschaften &#8230; <\/b>&ouml;ffnet ein Formular in der Entwurfsansicht, das schlicht ein Bezeichnungsfeld anzeigt. F&uuml;r dieses k&ouml;nnen wir hier die gew&uuml;nschten Eigenschaften wie Schriftart, Schriftgr&ouml;&szlig;e, Farbe et cetera einstellen. Nach dem Speichern und Schlie&szlig;en holt sich das Formular zum Erstellen neuer Detailformulare die Eigenschaften f&uuml;r die Schrift aus diesem Formular.<\/p>\n<p>Schlie&szlig;lich sehen wir im Unterformular noch die Liste der Felder der zugrunde liegenden Datensatzquelle. Diese wird nach der Auswahl der Tabelle oder Abfrage automatisch aufgrund der Daten der Datensatzquelle gef&uuml;llt.<\/p>\n<p>Wir k&ouml;nnen hier je Feld verschiedene Eigenschaften einstellen. Die erste lautet <b>IgnoreField <\/b>und erlaubt es, ein Feld durch das Setzen eines Hakens aus dem zu erstellenden Formular auszuschlie&szlig;en. <b>Fieldlabel<\/b> nimmt entweder, soweit vorhanden, den Wert der Eigenschaft <b>Beschriftung <\/b>aus dem Tabellenentwurf auf oder den Namen des Feldes. <b>Fieldindex<\/b> gibt die Reihenfolge an, in welcher die Felder angelegt werden sollen. Die Breite k&ouml;nnen wir individuell einstellen, genauso wie die H&ouml;he. Bei Feldern mit dem Felddatentyp <b>Langer Text <\/b>kann es sinnvoll sein, h&ouml;here Felder zu erstellen. <b>FieldColumn <\/b>ist ein vorbereitender Wert, falls wir noch mehrspaltige Detailformulare unterst&uuml;tzen. <b>ControlType <\/b>wird mit dem Steuerelementtyp entsprechend des Feldes aus der Tabelle gef&uuml;llt &#8211; normalerweise sind dies Textfelder (<b>109<\/b>), gelegentlich aber auch Kombinationsfelder (<b>111<\/b>) oder Kontrollk&auml;stchen (<b>106<\/b>). Die &uuml;brigen Eigenschaften sind Nachschlagefeldern vorbehalten und werden ebenfalls aus dem Tabellenentwurf entnommen. Wir k&ouml;nnen diese aber hier auch nachr&uuml;sten.<\/p>\n<h2>Detailformular erstellen<\/h2>\n<p>Ein Klick auf die Schaltfl&auml;che <b>Erstellen <\/b>sorgt schlie&szlig;lich daf&uuml;r, dass ein Formular auf Basis der get&auml;tigten Vorgaben erstellt wird (siehe Bild 4). Allein die akkurate Ausrichtung der Steuerelemente w&uuml;rde sonst einige Schritte erfordern, genau wie die manuelle Einstellung der verschiedenen Eigenschaften und des Hinzuf&uuml;gens der Schaltfl&auml;chen mit dem dahinter liegenden VBA-Code.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_004.png\" alt=\"Ein automatisch erstelltes Detailformular\" width=\"349,5589\" height=\"387,2307\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Ein automatisch erstelltes Detailformular<\/span><\/b><\/p>\n<h2>Tabellen der L&ouml;sung<\/h2>\n<p>Die L&ouml;sung verwendet aktuell drei Tabellen zum Speichern von Konfigurationsdaten. Die Tabelle <b>tblDetailforms <\/b>speichert die grundlegenden Daten je Formular. Die Tabelle <b>tblDetailfields <\/b>ist &uuml;ber das Fremdschl&uuml;sselfeld <b>DetailFormID <\/b>mit dieser Tabelle verbunden. Schlie&szlig;lich gibt es noch die Tabelle <b>tblButtonStyles <\/b>mit den grundlegenden Designeinstellungen f&uuml;r die Schaltfl&auml;chen. Der jeweilige Style wird &uuml;ber das Feld <b>ButtonStyleID <\/b>der Tabelle <b>tblDetailforms <\/b>selektiert (siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_005.png\" alt=\"Datenmodell des Add-Ins\" width=\"425,3444\" height=\"517,852\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Datenmodell des Add-Ins<\/span><\/b><\/p>\n<h2>Planung der L&ouml;sung als Access-Add-In<\/h2>\n<p>Wir wollen die L&ouml;sung dieses Beitrags sp&auml;ter als Access-Add-In bereitstellen, damit wir sie in beliebigen Datenbanken nutzen und damit Detailformulare erstellen k&ouml;nnen. Daher m&uuml;ssen wir an manchen Stellen etwas aufpassen. Zum Beispiel m&uuml;ssen wir unterschieden, ob wir im Code und in den Steuerelementen auf Daten der Add-In-Datenbank zugreifen oder auf die der Host-Datenbank, also der Datenbank, von der aus wir das Access-Ad-In aufgerufen haben.<\/p>\n<h2>Programmierung des Formulars frmDetailforms<\/h2>\n<p>Das Formular <b>frmDetailforms <\/b>soll beim Laden zun&auml;chst die Daten f&uuml;r die Kombinationsfelder bereitstellen.<\/p>\n<p>Die durch das Ereignis <b>Beim Laden <\/b>ausgel&ouml;ste Prozedur liest zuerst alle Tabellen und Abfragen der Datenbank ein, von der aus das Access-Add-In gestartet wurde (siehe Listing 1). Dies m&uuml;ssen wir mit dem <b>Database<\/b>-Objekt der Host-Datenbank erledigen, die wir mit <b>CurrentDb <\/b>referenzieren. Hier greifen wir auf die Tabelle <b>MSysObjects <\/b>zu, die alle Objekte der Datenbank enth&auml;lt. Wir filtern hier nach den Werten <b>1<\/b>, <b>4<\/b>, <b>5 <\/b>und <b>6 <\/b>im Feld <b>Type <\/b>und erhalten so alle Tabellen und Abfragen. Das so ermittelte Recordset weisen wir dem Kombinationsfeld <b>cboDatasource <\/b>zu.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\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>dbc<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;\">Dim <\/span>rstIcons<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT Name FROM MSysObjects WHERE Type IN (1, 4, 5, 6) AND Name NOT LIKE ''F_*'' \" _\r\n         & \"AND Name NOT LIKE ''MSys*'' AND Name NOT LIKE ''USys*'' AND Name NOT LIKE ''~*''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Set<\/span> Me!cboDatasource.Recordset = rst\r\n     <span style=\"color:blue;\">Set<\/span> rstIcons = dbc.OpenRecordset(\"SELECT id, [Name] FROM MSysResources WHERE Extension = ''png'' ORDER BY [Name]\", _\r\n         dbOpenDynaset)\r\n     <span style=\"color:blue;\">Set<\/span> Me!cboOKButtonIcon.Recordset = rstIcons\r\n     <span style=\"color:blue;\">Set<\/span> Me!cboCancelButtonIcon.Recordset = rstIcons\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Beim Laden des Formulars ausgel&ouml;ste Prozedur<\/span><\/b><\/p>\n<p>Die f&uuml;r die Schaltfl&auml;chen zu verwendenden Icons sollen jedoch aus der Tabelle <b>MSysResources<\/b> der Access-Add-In-Datenbank geholt werden. Diese referenzieren wir nicht mit <b>CurrentDb<\/b>, sondern mit <b>CodeDb<\/b>. Hier holen wir alle Elemente, deren Dateiendung auf png lautet und sortieren diese nach dem Namen. Dieses Recordset weisen wir der entsprechenden Eigenschaft der beiden Kombinationsfelder <b>cboOKButtonIcon <\/b>und <b>cboCancelButtonIcon <\/b>zu.<\/p>\n<h2>Felder der gew&auml;hlten Datensatzquelle einlesen<\/h2>\n<p>W&auml;hlen wir mit dem Kombinationsfeld <b>cboDatasource <\/b>eine Tabelle oder Abfrage aus, l&ouml;sen wir die folgende Prozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboDatasource_AfterUpdate()\r\n     <span style=\"color:blue;\">If <\/span>ReadFieldsFromTable(Me!cboDatasource) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         Me!sfmDetailforms.Form.Requery\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtFormname, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!txtFormname = <span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>( _\r\n             Me!cboDatasource, \"tbl\", \"frm\"), \"qry\", \"frm\")\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtFormTitle, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!txtFormTitle = <span style=\"color:blue;\">Replace<\/span>(<span style=\"color:blue;\">Replace<\/span>(_\r\n             Me!cboDatasource, \"tbl\", \"\"), \"qry\", \"\")\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese ruft eine weitere Funktion auf, die wir in Listing 2 sehen. Diese nimmt den Namen der Tabelle oder Abfrage als Parameter entgegen und speichert ihn in der Variablen <b>strDataSource<\/b>. Dann &ouml;ffnen wir ein Recordset auf Basis der Tabelle <b>tblDetailfields<\/b>, der wir die Feldinformationen zuweisen wollen. Das Recordset holt alle Datens&auml;tze, die mit dem aktuell im Hauptformular angezeigten Datensatz der Tabelle <b>tblDetailforms <\/b>verkn&uuml;pft sind. Die Prozedur bewegt den Datensatzzeiger auf den letzten Datensatz, um anschlie&szlig;end die Anzahl der enthaltenen Datens&auml;tze zu ermitteln. Ist diese nicht <b>0<\/b>, stellt die Prozedur dem Benutzer die Frage, ob die Felder neu eingelesen werden sollen. Bejaht der Benutzer dies, l&ouml;scht die Prozedur zun&auml;chst alle f&uuml;r diese Konfiguration bereits vorhandenen Datens&auml;tze aus der Tabelle <b>tblDetailfields<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ReadFieldsFromTable(strDataSource<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database, dbc<span style=\"color:blue;\"> As <\/span>DAO.Database, rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstSource<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>bolReadFields<span style=\"color:blue;\"> As Boolean<\/span>, intControlType<span style=\"color:blue;\"> As <\/span>AcControlType\r\n     <span style=\"color:blue;\">Dim <\/span>varRowSourceType<span style=\"color:blue;\"> As Variant<\/span>, varRowSource<span style=\"color:blue;\"> As Variant<\/span>, varBoundColumn<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>varCaption<span style=\"color:blue;\"> As Variant<\/span>, varColumnCount<span style=\"color:blue;\"> As Variant<\/span>, varColumnWidths<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>fld<span style=\"color:blue;\"> As <\/span>DAO.Field, i<span style=\"color:blue;\"> As Integer<\/span>\r\n     strDataSource = Me!cboDatasource\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = dbc.OpenRecordset(\"SELECT * FROM tblDetailfields WHERE DetailformID = \" & Me!DetailformID, 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         rst.MoveLast\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     bolReadFields = <span style=\"color:blue;\">True<\/span>\r\n     Me.Dirty = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.RecordCount = 0<span style=\"color:blue;\"> Then<\/span>\r\n         bolReadFields = <span style=\"color:blue;\">MsgBox<\/span>(\"Sollen die Felder neu eingelesen werden?\", vbYesNo + vbExclamation, _\r\n             \"Felder neu einlesen?\") = vbYes\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>bolReadFields = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         dbc.Execute \"DELETE FROM tblDetailfields WHERE DetailformID = \" & Me!DetailformID, dbFailOnError\r\n         <span style=\"color:blue;\">Set<\/span> rstSource = db.OpenRecordset(strDataSource, dbOpenDynaset)\r\n         For Each fld In rstSource.Fields\r\n             <span style=\"color:blue;\">Call<\/span> GetControlProperties(fld, varCaption, intControlType, varBoundColumn, varRowSourceType, _\r\n                 varRowSource, varColumnCount, varColumnWidths)\r\n             rst.Add<span style=\"color:blue;\">New<\/span>\r\n             rst!DetailformID = Me!txtDetailformID\r\n             rst!FieldName = fld.Name\r\n             rst!Fieldindex = i\r\n             rst!FieldWidth = 2000\r\n             rst!Fieldheight = 300\r\n             rst!FieldColumn = 1\r\n             rst!Fieldlabel = Nz(varCaption, fld.Name)\r\n             rst!ControlType = intControlType\r\n             rst!RowSourceType = varRowSourceType\r\n             rst!RowSource = varRowSource\r\n             rst!BoundColumn = varBoundColumn\r\n             rst!ColumnCount = varColumnCount\r\n             rst!ColumnWidths = varColumnWidths\r\n             rst.Update\r\n             i = i + 1\r\n         <span style=\"color:blue;\">Next<\/span> fld\r\n         ReadFieldsFromTable = <span style=\"color:blue;\">True<\/span>\r\n         Me!sfmDetailforms.Form.Requery\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         ReadFieldsFromTable = <span style=\"color:blue;\">False<\/span>\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 2: Einlesen der Feldinformationen in die Tabelle tblDetailfields<\/span><\/b><\/p>\n<p>Nun referenziert sie mit einem zweiten Recordset die Tabelle, f&uuml;r die wir das Detailformular erstellen wollen, mit der Variablen <b>rstSource<\/b>. F&uuml;r diese durchlaufen wir alle in der <b>Fields<\/b>-Auflistung enthaltenen <b>Field<\/b>-Elemente und referenzieren das aktuelle Element jeweils mit der Variablen <b>fld<\/b>.<\/p>\n<p>Hier rufen wir nun eine weitere Funktion namens <b>GetControlProperties <\/b>auf und &uuml;bergeben dieser einen Verweis auf das zu untersuchende Feld. Au&szlig;erdem &uuml;bergeben wir einige <b>Variant<\/b>-Variablen, die wir mit den Werten der entsprechenden Eigenschaften des Feldes f&uuml;llen wollen &#8211; diese beschreiben wir gleich im Anschluss.<\/p>\n<p>Nachdem wir die verschiedenen <b>Variant<\/b>-Variablen mit den Eigenschaften des Feldes <b>fld <\/b>gef&uuml;llt haben, legen wir einen neuen Datensatz im Recordset der Tabelle <b>tblDetailfields <\/b>an und f&uuml;llen nacheinander die Eigenschaften. Dazu geh&ouml;ren der Verweis auf den aktuellen Eintrag der Tabelle <b>tblDetailforms<\/b>, der Feldname, der Index, Voreinstellungen von 2.000 und 300 Pixeln f&uuml;r die Steuerelementbreite und -h&ouml;he und der Wert <b>1 <\/b>f&uuml;r die Spalte. Danach folgen die Beschriftung f&uuml;r das Steuerelement, der Steuerelementtyp und dann einige Eigenschaften, die nur f&uuml;r Nachschlagefelder ben&ouml;tigt werden. Danach speichern wir den neuen Datensatz mit der <b>Update<\/b>-Methode und liefern der aufrufenden Prozedur den Wert <b>True <\/b>zur&uuml;ck.<\/p>\n<p>Die aufrufende Prozedur <b>cboDatasource_AfterUpdate<\/b> pr&uuml;ft schlie&szlig;lich noch, ob <b>txtFormname <\/b>und <b>txtFormTitel <\/b>bereits gef&uuml;llt sind. Falls nicht, tr&auml;gt sie f&uuml;r <b>txtFormname <\/b>einen Wert ein, der dem Tabellen- oder Abfragenamen entspricht, aber das Pr&auml;fix <b>tbl <\/b>oder <b>qry <\/b>durch <b>frm <\/b>ersetzt. F&uuml;r das Feld <b>txtFormTitle <\/b>tr&auml;gt die Prozedur ebenfalls den Namen der Datenquelle ein, ersetzt aber die Pr&auml;fixe <b>tbl <\/b>und <b>qry <\/b>ersatzlos.<\/p>\n<h2>Ermitteln von Feldeigenschaften<\/h2>\n<p>Die bereits angesprochene Funktion <b>GetControlProperties <\/b>nimmt einen Verweis auf ein <b>Field<\/b>-Objekt entgegen und ermittelt einige Eigenschaften dieses Feldes (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetControlProperties(fld<span style=\"color:blue;\"> As <\/span>DAO.Field, varCaption<span style=\"color:blue;\"> As Variant<\/span>, intControlType<span style=\"color:blue;\"> As <\/span>AcControlType, _\r\n         varBoundColumn<span style=\"color:blue;\"> As Variant<\/span>, varRowSourceType<span style=\"color:blue;\"> As Variant<\/span>, varRowSource<span style=\"color:blue;\"> As Variant<\/span>, varColumnCount<span style=\"color:blue;\"> As Variant<\/span>, _\r\n         varColumnWidths<span style=\"color:blue;\"> As Variant<\/span>)\r\n     intControlType = 0\r\n     varCaption = Null\r\n     varBoundColumn = Null\r\n     varRowSourceType = Null\r\n     varRowSource = Null\r\n     varColumnCount = Null\r\n     varColumnWidths = Null\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     varCaption = fld.Properties(\"Caption\")\r\n     intControlType = fld.Properties(\"DisplayControl\")\r\n     Select Case intControlType\r\n         <span style=\"color:blue;\">Case <\/span>acTextBox\r\n             <span style=\"color:blue;\">Debug.Print<\/span> fld.Name, \"acTextBox\"\r\n         <span style=\"color:blue;\">Case <\/span>acComboBox\r\n             varBoundColumn = fld.Properties(\"BoundColumn\")\r\n             varRowSourceType = fld.Properties(\"RowSourceType\")\r\n             varRowSource = fld.Properties(\"RowSource\")\r\n             varColumnCount = fld.Properties(\"ColumnCount\")\r\n             varColumnWidths = fld.Properties(\"ColumnWidths\")\r\n         <span style=\"color:blue;\">Case <\/span>acCheckBox\r\n             <span style=\"color:blue;\">Debug.Print<\/span> fld.Name, \"acCheckBox\"\r\n         <span style=\"color:blue;\">Case Else<\/span>\r\n             <span style=\"color:blue;\">Debug.Print<\/span> \"anderer Controltype\", intControlType\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Ermitteln verschiedener Feldeigenschaften<\/span><\/b><\/p>\n<p>Dabei deaktivieren wir zuerst die eingebaute Fehlerbehandlung und greifen dann auf die beiden Eigenschaften <b>Caption <\/b>und <b>DisplayControl <\/b>zu. <b>Caption <\/b>wird nur gesetzt, wenn wir im Tabellenentwurf die Eigenschaft Beschriftung f&uuml;r ein Feld f&uuml;llen. <b>DisplayControl <\/b>wird nur angelegt, wenn wir ein Nachschlagefeld anlegen oder ein <b>Ja<\/b>\/<b>Nein<\/b>-Feld. Daher l&ouml;st der Zugriff auf eine solche Eigenschaft einen Fehler aus, wenn diese nicht vorhanden ist. Wir lesen diese bei deaktivierter Fehlerbehandlung ein und pr&uuml;fen danach zuerst den Wert von <b>intControlType<\/b>.<\/p>\n<p>Abh&auml;ngig von diesem Wert lesen wir weitere Informationen ein &#8211; beim Wert acComboBox zum Beispiel noch die gebundene Spalte, den Herkunftstyp, die Datensatzherkunft, die Anzahl der Spalten und die Spaltenbreiten.<\/p>\n<p>Danach geben wir die entsprechenden Informationen mit den <b>Variant<\/b>-Parametern an die aufrufende Prozedur <b>ReadFieldsFromTable <\/b>zur&uuml;ck, welche diese in den entsprechenden neuen Datensatz der Tabelle <b>tblDetailfields <\/b>schreibt.<\/p>\n<p>Die Tabelle <b>tblDetailfields <\/b>sieht nach diesem Schritt beispielsweise wie in Bild 6 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/6pic_1490_005.png\" alt=\"Werte der Tabelle tblDetailfields nach dem Einlesen der Felder der Quelltabelle\" width=\"700\" height=\"239,6279\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Werte der Tabelle tblDetailfields nach dem Einlesen der Felder der Quelltabelle<\/span><\/b><\/p>\n<h2>Button-Style ausw&auml;hlen und einstellen<\/h2>\n<p>Klicken wir auf die Schaltfl&auml;che <b>cmdButtonStyles<\/b>, l&ouml;sen wir die folgende Prozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdButtonStyles_Click()\r\n     DoCmd.OpenForm \"frmButtonStyles\", _\r\n         WindowMode:=acDialog, OpenArgs:=Me!cboButtonStyleID\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmButtonStyles\")<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cboButtonStyleID = _\r\n             Forms!frmButtonStyles!ButtonStyleID\r\n         DoCmd.Close acForm, \"frmButtonStyles\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese &ouml;ffnet das Formular <b>frmButtonStyles<\/b>, das an die Tabelle <b>tblButtonStyles <\/b>gebunden ist und in der Entwurfsansicht wie in Bild 7 aussieht. Dieses Formular ruft beim Anzeigen eines Datensatzes die folgende Prozedur auf:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_006.png\" alt=\"Entwurfsansicht des Formulars frmButtonStyles\" width=\"425,3444\" height=\"244,8696\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Entwurfsansicht des Formulars frmButtonStyles<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">Call<\/span> SetButtonStyle\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese startet eine weitere Prozedur namens <b>SetButtonStyle<\/b>. Diese wendet die aktuellen Einstellungen auf das f&uuml;r die Vorschau verwendete <b>Button<\/b>-Element <b>cmdPreview <\/b>an:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>SetButtonStyle()\r\n     <span style=\"color:blue;\">With<\/span> Me!cmdPreview\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!cboBorderStyle)<span style=\"color:blue;\"> Then<\/span>\r\n             .BorderStyle = Me!cboBorderStyle\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!cboBackStyle)<span style=\"color:blue;\"> Then<\/span>\r\n             .BackStyle = Me!cboBackStyle\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNull(Me!cboAlignment)<span style=\"color:blue;\"> Then<\/span>\r\n             .Alignment = Me!cboAlignment\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 Sub<\/span><\/pre>\n<p>Diese Prozedur wird auch durch die &uuml;brigen Steuerelemente zum Einstellen der Eigenschaften aufgerufen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>BorderStyle_AfterUpdate()\r\n     <span style=\"color:blue;\">Call<\/span> SetButtonStyle\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cboAlignment_AfterUpdate()\r\n     <span style=\"color:blue;\">Call<\/span> SetButtonStyle\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cboBackStyle_AfterUpdate()\r\n     <span style=\"color:blue;\">Call<\/span> SetButtonStyle\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cboBorderStyle_AfterUpdate()\r\n     <span style=\"color:blue;\">Call<\/span> SetButtonStyle\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Beim Anklicken der <b>OK<\/b>-Schaltfl&auml;che wird das Formular unsichtbar gemacht:<\/p>\n<pre><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>Dadurch l&auml;uft der aufrufende Code weiter und pr&uuml;ft, ob das Formular <b>frmButtonStyles <\/b>noch ge&ouml;ffnet ist. Ist das der Fall, liest sie den aktuellen Datensatz aus dem Formular ein und w&auml;hlt diesen im Kombinationsfeld <b>cboButtonStyleID <\/b>aus.<\/p>\n<h2>Start der Erstellung des Detailformulars<\/h2>\n<p>Nun schauen wir uns an, was geschieht, wenn wir alle notwendigen Einstellungen getroffen haben und die <b>Erstellen<\/b>-Schaltfl&auml;che bet&auml;tigen. Diese hat den folgenden Code und speichert erst einmal die aktuellen Einstellungen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdCreate_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidth<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngHeight<span style=\"color:blue;\"> As Long<\/span>\r\n     RunCommand acCmdSaveRecord\r\n     <span style=\"color:blue;\">If <\/span>CreateNewForm(Me!Formname) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         DoCmd.OpenForm Me!Formname, acDesign\r\n         <span style=\"color:blue;\">Set<\/span> frm = Forms(Me!Formname)\r\n         <span style=\"color:blue;\">With<\/span> frm\r\n             .AutoCenter = Me!chkAutocenter\r\n             .Caption = Me!txtFormTitle\r\n             .DefaultView = acDefViewSingle\r\n             .RecordSelectors = Me!chkRecordSelectors\r\n             .NavigationButtons = Me!chkNavigationButtons\r\n             .DividingLines = <span style=\"color:blue;\">False<\/span>\r\n             .ScrollBars = Me!cboScrollBars\r\n             .RecordSource = Me!cboDatasource\r\n             .Cycle = Me!cboCycle\r\n             .HasModule = <span style=\"color:blue;\">True<\/span>\r\n             AddControls Me!DetailformID, lngHeight, lngWidth\r\n             .Section(0).Height = lngHeight\r\n             .Width = lngWidth\r\n         End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Danach ruft sie die Funktion <b>CreateNewForm <\/b>auf, der sie den Formularnamen &uuml;bergibt  (siehe Listing 4). Die Funktion beschreiben wir weiter unten. Sie erstellt ein neues Formular und speichert es unter dem angegebenen Namen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CreateNewForm(strName<span style=\"color:blue;\"> As String<\/span>)<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>strNameTemp<span style=\"color:blue;\"> As String<\/span>\r\n      <span style=\"color:blue;\">If <\/span>ExistsForm(strName)<span style=\"color:blue;\"> Then<\/span>\r\n          If <span style=\"color:blue;\">MsgBox<\/span>(\"Formular ''\" & strName & \"'' ist bereits vorhanden. &Uuml;berschreiben?\", vbYesNo + vbExclamation, _\r\n                  \"Formular &uuml;berschreiben\") = vbYes Then\r\n              <span style=\"color:blue;\">If <\/span>DeleteForm(strName) = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/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;\">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;\">Set<\/span> frm = CreateForm()\r\n      strNameTemp = frm.Name\r\n      frm.Visible = <span style=\"color:blue;\">True<\/span>\r\n      DoCmd.Close acForm, frm.Name, acSaveYes\r\n      DoCmd.Rename strName, acForm, strNameTemp\r\n      CreateNewForm = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Erstellen des Formulars<\/span><\/b><\/p>\n<p>Dieses &ouml;ffnen wir dann in der Entwurfsansicht und referenzieren es mit der Variablen <b>frm<\/b>. Dann stellen wir die Eigenschaften des Formulars ein, die wir im Formular konfiguriert haben. Au&szlig;erdem stellen wir die Eigenschaft <b>HasModule <\/b>auf den Wert <b>True <\/b>ein und legen so direkt ein VBA-Klassenmodul f&uuml;r dieses Formular an. Schlie&szlig;lich rufen wir die Prozedur <b>AddControls<\/b> auf, die das Hinzuf&uuml;gen der einzelnen Steuerelemente &uuml;bernimmt &#8211; auch diese beschreiben wir weiter unten im Detail.<\/p>\n<p>Hier ist nur wichtig, dass wir dieser Prozedur die Nummer der Konfiguration aus der Tabelle <b>tblDetailforms <\/b>&uuml;bergeben und zwei Parameter mit denen wir die H&ouml;he und die Breite zur&uuml;ckerhalten, die f&uuml;r die Steuerelemente ben&ouml;tigt wird. Diese verwenden wir dann, um die H&ouml;he des Detailbereichs und die Breite des Formulars genau an die enthaltenen Steuerelemente anzupassen.<\/p>\n<h2>Erstellen des Formulars selbst<\/h2>\n<p>Die Funktion <b>CreateNewForm <\/b>&uuml;bernimmt die eigentliche Erstellung des leeren Formulars. Dazu erh&auml;lt sie den Namen des zu neuen Formulars als Parameter.<\/p>\n<p>Die Funktion pr&uuml;ft als Erstes mit der Funktion <b>ExistsForm<\/b>, ob bereits ein Formular mit dem angegebenen Namen existiert:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ExistsForm(strForm<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n      <span style=\"color:blue;\">Dim <\/span>objForm<span style=\"color:blue;\"> As <\/span>AccessObject\r\n      For Each objForm In CurrentProject.AllForms\r\n          <span style=\"color:blue;\">If <\/span>objForm.Name = strForm<span style=\"color:blue;\"> Then<\/span>\r\n              ExistsForm = <span style=\"color:blue;\">True<\/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;\">Next<\/span> objForm\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Ist das der Fall, fragt die Funktion <b>CreateNewForm <\/b>den Benutzer, ob er das Formular &uuml;berschreiben m&ouml;chte. Stimmt er dem zu, l&ouml;scht die Funktion <b>DeleteForm <\/b>das Formular mit der <b>DeleteObject<\/b>-Methode:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DeleteForm(strName<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n      On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n      DoCmd.DeleteObject acForm, strName\r\n      <span style=\"color:blue;\">If <\/span>Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n          DeleteForm = <span style=\"color:blue;\">True<\/span>\r\n      <span style=\"color:blue;\">Else<\/span>\r\n          <span style=\"color:blue;\">MsgBox<\/span> Err.Description, <span style=\"color:blue;\">vbCr<\/span>itical + vbOKOnly, _\r\n              \"L&ouml;schen fehlgeschlagen\"\r\n      <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Die Funktion <b>CreateNewForm <\/b>erstellt dann mit der Methode <b>CreateForm <\/b>ein neues, leeres Formular und speichert dessen Namen in der Variablen <b>strNameTemp<\/b>.<\/p>\n<p>Dann macht sie das Formular sichtbar und schlie&szlig;t es unter dem tempor&auml;ren Namen. Anschlie&szlig;end benennt sie das Formular mit der Methode <b>Rename <\/b>in den gew&uuml;nschten Namen um.<\/p>\n<h2>Hinzuf&uuml;gen der Steuerelemente<\/h2>\n<p>Das Hinzuf&uuml;gen der Steuerelemente &uuml;bernimmt die Prozedur <b>AddControls <\/b>aus Listing 5. Dieser &uuml;bergeben wir die ID des Formulars, dessen Steuerelemente hinzugef&uuml;gt werden sollen. Die Prozedur referenziert das <b>Database<\/b>-Objekt mit der Variablen <b>dbc<\/b>. Dann erstellt sie ein Recordset auf Basis des Datensatzes der Tabelle <b>tblDetailforms<\/b>, f&uuml;r den wir das neue Formular mit Steuerelementen f&uuml;llen wollen. Hier lesen wir den Formularnamen aus und tragen ihn in <b>strFormName <\/b>ein.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AddControls(lngDetailformID<span style=\"color:blue;\"> As Long<\/span>, lngHeight<span style=\"color:blue;\"> As Long<\/span>, lngWidth<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database, rstControls<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstForm<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstButtonStyles<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strFormName<span style=\"color:blue;\"> As String<\/span>, ctl<span style=\"color:blue;\"> As <\/span>Control, cmd<span style=\"color:blue;\"> As <\/span>CommandButton\r\n     <span style=\"color:blue;\">Dim <\/span>lngLeft<span style=\"color:blue;\"> As Long<\/span>, lngMaxWidth<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngLabelWidth<span style=\"color:blue;\"> As Long<\/span>, lngTop<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rstForm = dbc.OpenRecordset(\"SELECT * FROM tblDetailforms WHERE DetailformID = \" & lngDetailformID, _\r\n         dbOpenDynaset)\r\n     strFormName = rstForm!Formname\r\n     <span style=\"color:blue;\">Set<\/span> rstControls = dbc.OpenRecordset(\"SELECT * FROM tblDetailfields WHERE DetailformID = \" & lngDetailformID, _\r\n         dbOpenDynaset)\r\n     lngLabelWidth = GetMaxLabelWidth(rstControls)\r\n     lngTop = rstForm!Margin\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstControls.EOF\r\n         <span style=\"color:blue;\">If <\/span>rstControls!IgnoreField = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             Select Case rstControls!ControlType\r\n                 <span style=\"color:blue;\">Case <\/span>acTextBox\r\n                     <span style=\"color:blue;\">Set<\/span> ctl = AddTextBox(rstForm, rstControls, strFormName, acDetail, lngLabelWidth, lngTop, _\r\n                         lngMaxWidth)\r\n                 <span style=\"color:blue;\">Case <\/span>acComboBox\r\n                     <span style=\"color:blue;\">Set<\/span> ctl = AddComboBox(rstForm, rstControls, strFormName, acDetail, lngLabelWidth, lngTop, _\r\n                         lngMaxWidth)\r\n                 <span style=\"color:blue;\">Case <\/span>acCheckBox\r\n                     <span style=\"color:blue;\">Set<\/span> ctl = AddCheckBox(rstForm, rstControls, strFormName, acDetail, lngLabelWidth, lngTop, _\r\n                         lngMaxWidth)\r\n                 <span style=\"color:blue;\">Case Else<\/span>\r\n                     <span style=\"color:blue;\">Set<\/span> ctl = AddTextBox(rstForm, rstControls, strFormName, acDetail, lngLabelWidth, lngTop, _\r\n                         lngMaxWidth)\r\n             <span style=\"color:blue;\">End Select<\/span>\r\n             lngTop = lngTop + ctl.Height + rstForm!Margin\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         rstControls.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     lng<span style=\"color:blue;\">Left<\/span> = rstForm!Margin\r\n     <span style=\"color:blue;\">Set<\/span> rstButtonStyles = dbc.OpenRecordset(\"SELECT * FROM tblButtonStyles WHERE ButtonStyleID = \" _\r\n         & rstForm!ButtonStyleID, dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span>rstForm!OKButton = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> cmd = AddButton(rstForm, rstButtonStyles, \"OK\", lngLeft, lngTop, lngMaxWidth)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>rstForm!CancelButton = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> cmd = AddButton(rstForm, rstButtonStyles, \"Cancel\", lngLeft, lngTop, lngMaxWidth)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     lngHeight = lngTop + 50 + cmd.Height + rstForm!Margin\r\n     lngWidth = lngMaxWidth + rstForm!Margin\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Hinzuf&uuml;gen der Steuerelemente<\/span><\/b><\/p>\n<p>Dann f&uuml;llen wir ein weiteres Recordset namens <b>rstControls <\/b>mit allen Datens&auml;tzen der Tabelle <b>tblDetailfields<\/b> f&uuml;r das zu erstellende Formular. Mit diesem Recordset als Parameter rufen wir die Funktion <b>GetMaxLabelWidth <\/b>auf, mit der wir die optimale Breite f&uuml;r die Bezeichnungsfelder der anzulegenden Felder berechnen &#8211; siehe weiten unten.<\/p>\n<p>Anschlie&szlig;end legen wir den Abstand vom oberen Formularrand f&uuml;r das erste anzulegende Element fest. Diesen Abstand beziehen wir aus dem Feld <b>Margin<\/b> der Tabelle <b>tblDetailforms<\/b>.<\/p>\n<p>Damit starten wir in eine <b>Do While<\/b>-Schleife &uuml;ber alle Elemente des Recordsets <b>rstControls<\/b>. Hier pr&uuml;fen wir als Erstes den Wert des Feldes <b>IgnoreField<\/b>. Wenn wir hier den Wert <b>True <\/b>vorfinden, wird das Feld nicht f&uuml;r das Detailformular ber&uuml;cksichtigt.<\/p>\n<p>Anderenfalls pr&uuml;fen wir in einer <b>Select Case<\/b>-Bedingung den Steuerelementtyp des Feldes. Abh&auml;ngig vom jeweiligen Wert, also <b>acTextBox<\/b>, <b>acComboBox <\/b>oder <b>acCheckBox<\/b>, rufen wir eine der Funktionen <b>AddTextBox<\/b>, <b>AddComboBox <\/b>oder <b>AddCheckBox <\/b>auf.<\/p>\n<p>Diesen &uuml;bergeben wir die zum Anlegen notwendigen Informationen und erhalten im Gegenzug einen Verweis auf das jeweilige Steuerelement zur&uuml;ck.<\/p>\n<p>Damit k&ouml;nnen wir die H&ouml;he des angelegten Steuerelements ermitteln und f&uuml;r die Variable <b>lngTop <\/b>den Abstand vom oberen Formularrand f&uuml;r das n&auml;chste Steuerelement ermitteln. Dazu addieren wir zum aktuellen Wert von <b>lngTop <\/b>die H&ouml;he des zuletzt hinzugef&uuml;gten Steuerelements und den vorgegebenen allgemeinen Abstand aus dem Feld <b>Margin <\/b>der Tabelle <b>tblDetailforms<\/b>.<\/p>\n<p>Danach pr&uuml;fen wir noch, ob der Benutzer eine <b>OK<\/b>-Schaltfl&auml;che und\/oder eine <b>Abbrechen<\/b>-Schaltfl&auml;che hinzuf&uuml;gen m&ouml;chte. In diesem Fall rufen wir jeweils die Funktion <b>AddButton <\/b>auf, die wir weiter unten beschreiben.<\/p>\n<p>Schlie&szlig;lich ermitteln wir aus der Position des zuletzt angelegten <b>Button<\/b>-Elements die H&ouml;he des Detailbereichs, die wir in <b>lngHeight <\/b>schreiben, und auf &auml;hnliche Weise berechnen wir die Breite des Formulars f&uuml;r die angelegten Steuerelemente.<\/p>\n<h2>Maximale Breite der Bezeichnungsfelder ermitteln<\/h2>\n<p>In der Prozedur <b>AddControls <\/b>nutzen wir noch die Funktion <b>GetMaxLabelWidth<\/b>, um die maximale Breite f&uuml;r die Beschriftungsfelder zu ermitteln (siehe Listing 6). Diese nimmt ein Recordset mit den Daten der Tabelle <b>tblDetailfields <\/b>f&uuml;r das anzulegende Detailformular entgegen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetMaxLabelWidth(rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset)\r\n     <span style=\"color:blue;\">Dim <\/span>frm<span style=\"color:blue;\"> As <\/span>Form\r\n     <span style=\"color:blue;\">Dim <\/span>lbl<span style=\"color:blue;\"> As <\/span>Label\r\n     <span style=\"color:blue;\">Dim <\/span>lngBold<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidthText<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngHeight<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidthMax<span style=\"color:blue;\"> As Long<\/span>\r\n     DoCmd.OpenForm \"frmFontStyles\"\r\n     <span style=\"color:blue;\">Set<\/span> frm = Forms!frmFontStyles\r\n     <span style=\"color:blue;\">Set<\/span> lbl = frm!lblFontStyle\r\n     WizHook.Key = 51488399\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         <span style=\"color:blue;\">With<\/span> lbl\r\n             <span style=\"color:blue;\">If <\/span>.FontBold<span style=\"color:blue;\"> Then<\/span>\r\n                 lngBold = 700\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 lngBold = 400\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             WizHook.TwipsFromFont .FontName, .FontSize, lngBold, .FontItalic, .FontUnderline, 0, rst!Fieldlabel & \":\", _\r\n                 0, lngWidthText, lngHeight\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         <span style=\"color:blue;\">If <\/span>lngWidthText &gt; lngWidthMax<span style=\"color:blue;\"> Then<\/span>\r\n             lngWidthMax = lngWidthText\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     rst.MoveFirst\r\n     GetMaxLabelWidth = lngWidthMax\r\n     DoCmd.Close acForm, \"frmFontStyles\"\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Ermitteln der maximalen Breite f&uuml;r die Label-Elemente<\/span><\/b><\/p>\n<p>Sie &ouml;ffnet dann ein Formular namens <b>frmFontStyles<\/b>. Wozu dient dieses? Wir k&ouml;nnen dieses in der Entwurfsansicht &ouml;ffnen und stellen f&uuml;r das darin enthaltene Bezeichnungsfeld <b>lblFontStyle <\/b>die gew&uuml;nschten Einstellungen f&uuml;r die Schriftart ein (siehe Bild 8).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_003.png\" alt=\"Formular zum Einstellen der Schriftart f&uuml;r die Label\" width=\"649,559\" height=\"245,6247\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Formular zum Einstellen der Schriftart f&uuml;r die Label<\/span><\/b><\/p>\n<p>Die Funktion <b>GetMaxLabelWidth <\/b>referenziert das Formular, das in der Entwurfsansicht ge&ouml;ffnet wurde, und das darin enthaltene Bezeichnungsfeld <b>lblFontStyle<\/b>. <\/p>\n<p>Dann beginnt ein Vorgang, den wir in einer Do While-Schleife f&uuml;r alle Bezeichnungsfelder des zu erstellenden Formulars ausf&uuml;hren. <\/p>\n<p>Dabei ruft die Funktion die Methode <b>TwipsFromFont <\/b>der nicht dokumentierten <b>WizHook<\/b>-Klasse auf. Dieser &uuml;bergeben wir die Eigenschaften bez&uuml;glich der Schriftart und des Textes des Bezeichnungsfeldes.<\/p>\n<p>Die Methode <b>TwipsFromFont <\/b>f&uuml;llt die beiden R&uuml;ckgabeparameter <b>lngWidthText <\/b>und <b>lngHeight <\/b>mit der Breite und H&ouml;he, den die &uuml;bergebenen Texte in der Schriftart des Bezeichnungsfeldes einnehmen w&uuml;rden.<\/p>\n<p>Die Funktion vergleicht den mit <b>lngWidthText <\/b>gelieferten Wert nun mit dem Wert der Variablen <b>lngWidthMax<\/b>. Ist dieser gr&ouml;&szlig;er als <b>lngWidthMax<\/b>, stellt sie <b>lngWidthMax <\/b>auf <b>lngWidthText <\/b>ein.<\/p>\n<p>Auf diese Weise erhalten wir anschlie&szlig;end die Breite des breitesten Beschriftungstextes und geben diesen als Funktionswert zur&uuml;ck. Zuletzt schlie&szlig;t die Funktion das Formular <b>frmFontStyles <\/b>wieder.<\/p>\n<h2>Anlegen der einzelnen Steuerelemente<\/h2>\n<p>Die Prozedur <b>AddControls <\/b>ermittelt, wie wir zuvor gesehen haben, anhand der in der Tabelle <b>tblDetailfields <\/b>angegebenen Daten den Typ des Steuerelements, den wir anlegen m&uuml;ssen.<\/p>\n<p>Dementsprechend ruft es eine der Funktionen <b>AddTextBox<\/b>, <b>AddComboBox <\/b>oder <b>AddCheckBox <\/b>auf. Sollen zus&auml;tzlich noch Schaltfl&auml;chen hinzugef&uuml;gt werden, erfolgen noch Aufrufe der Funktion <b>AddButton<\/b>. Diese Funktionen beschreiben wir in den folgenden Abschnitten.<\/p>\n<h2>Funktion zum Anlegen von Schaltfl&auml;chen<\/h2>\n<p>Die Funktion <b>AddButton <\/b>aus Listing 7 nimmt Verweise auf das Recordset auf Basis der Tabelle <b>tblDetailforms <\/b>entgegen sowie auf das Recordset mit den Daten der Tabelle <b>tblButtonStyles<\/b>. Au&szlig;erdem werden noch einige weitere Parameter &uuml;bergeben, zum Beispiel mit <b>strBtnLbl <\/b>einer der Werte <b>OK <\/b>oder <b>Cancel<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddButton(rstForm<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstButtonStyles<span style=\"color:blue;\"> As <\/span>DAO.Recordset, strBtnLbl<span style=\"color:blue;\"> As String<\/span>, _\r\n         lngLeft<span style=\"color:blue;\"> As Long<\/span>, lngTop<span style=\"color:blue;\"> As Long<\/span>, lngMaxWidth<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>cmd<span style=\"color:blue;\"> As <\/span>CommandButton\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidthBase<span style=\"color:blue;\"> As Long<\/span>, lngBold<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngWidthText<span style=\"color:blue;\"> As Long<\/span>, lngHeightText<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngIconID<span style=\"color:blue;\"> As Long<\/span>, strIconName<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> cmd = CreateControl(rstForm!Formname, acCommandButton, acDetail, , , lngLeft, lngTop + 50, 2000, 400)\r\n     <span style=\"color:blue;\">With<\/span> cmd\r\n         lngIconID = Nz(rstForm(strBtnLbl & \"ButtonIcon\"), 0)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> lngIconID = 0<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>CopyIcon(lngIconID) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n                 strIconName = CodeDb.OpenRecordset(\"SELECT Name FROM MSysResources WHERE ID = \" & lngIconID).Fields(0)\r\n                 .Picture = strIconName \r\n                 .PictureCaptionArrangement = acRight\r\n             <span style=\"color:blue;\">End If<\/span>\r\n             .Caption = \" \" & rstForm(strBtnLbl & \"ButtonCaption\")\r\n             lngWidthBase = 550\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             .Caption =  rstForm(strBtnLbl & \"ButtonCaption\")\r\n             lngWidthBase = 200\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         .BorderStyle = rstButtonStyles!BorderStyle\r\n         .BackStyle = rstButtonStyles!BackStyle\r\n         .Alignment = rstButtonStyles!Alignment\r\n         <span style=\"color:blue;\">If <\/span>strBtnLbl = \"OK\"<span style=\"color:blue;\"> Then<\/span>\r\n             .Default = rstForm!OKButtonAsStandard\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span>strBtnLbl = \"Cancel\"<span style=\"color:blue;\"> Then<\/span>\r\n             .Cancel = rstForm!CancelButtonAsCancel\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         .Name = \"cmd\" & strBtnLbl\r\n         WizHook.Key = 51488399\r\n         <span style=\"color:blue;\">If <\/span>.FontBold<span style=\"color:blue;\"> Then<\/span>\r\n             lngBold = 700\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             lngBold = 400\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         WizHook.TwipsFromFont .FontName, .FontSize, lngBold, .FontItalic, .FontUnderline, 0, .Caption, 0, _\r\n             lngWidthText, lngHeightText\r\n         .Width = lngWidthBase + lngWidthText\r\n         lng<span style=\"color:blue;\">Left<\/span> = lng<span style=\"color:blue;\">Left<\/span> + .Width + 150\r\n         AddButtonEvent Forms(rstForm!Formname), cmd, rstForm(strBtnLbl & \"Code\")\r\n         <span style=\"color:blue;\">If <\/span>cmd.<span style=\"color:blue;\">Left<\/span> + cmd.Width &gt; lngMaxWidth<span style=\"color:blue;\"> Then<\/span>\r\n             lngMaxWidth = cmd.<span style=\"color:blue;\">Left<\/span> + cmd.Width\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> AddButton = cmd\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Anlegen einer Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Die Routine nutzt die Funktion <b>CreateControl<\/b>, um ein neues <b>Button<\/b>-Element anzulegen. Dabei &uuml;bergibt es verschiedene Informationen:<\/p>\n<ul>\n<li>den Namen des Zielformulars (aus <b>rstForm!Formname<\/b>),<\/li>\n<li>den Typ des Steuerelements (<b>acCommandButton<\/b>),<\/li>\n<li>den Zielbereich (<b>acDetail<\/b>)<\/li>\n<li>und die Koordinaten f&uuml;r das anzulegende Steuerelement.<\/li>\n<\/ul>\n<p><b>CreateControl <\/b>gibt einen Verweis auf das erstellte Steuerelement zur&uuml;ck und wir speichern diesen in der Variablen <b>cmd<\/b>. In einer <b>If&#8230;Then<\/b>-Bedingung pr&uuml;fen wir, ob f&uuml;r das Feld <b>OKButtonIcon <\/b>oder <b>CancelButtonIcon <\/b>die Nummer eines anzuzeigenden Icons hinterlegt wurde. Ist das der Fall, kopieren wir dieses Icon mit der Funktion <b>CopyIcon<\/b>, die wir weiter unten erl&auml;utern, aus der <b>MSysResources<\/b>-Tabelle der Add-In-Datendatenbank in die <b>MSysResources<\/b>-Tabelle der Zieldatenbank. Damit die Schaltfl&auml;che dieses Icon anschlie&szlig;end anzeigt, stellen wir die Eigenschaft <b>Picture <\/b>auf den Namen dieses Icons aus der Tabelle <b>MSysResources <\/b>der Zieldatei ein. Au&szlig;erdem sorgen wir daf&uuml;r, dass die Beschriftung rechts vom Icon angezeigt wird. Diese legen wir &uuml;ber die Eigenschaft <b>Caption <\/b>auf den Wert aus dem Feld <b>OKButtonCaption <\/b>oder <b>CancelButtonCaption <\/b>fest.<\/p>\n<p>Falls kein Icon vorhanden ist, stellen wir einfach nur die Beschriftung auf diesen Wert ein. Danach legen wir weitere Eigenschaften entsprechend der f&uuml;r dieses Formular angegebenen Werte in der Tabelle <b>tblButtonStyles <\/b>an, stellen die Eigenschaften <b>Default <\/b>und <b>Cancel <\/b>f&uuml;r die Schaltfl&auml;che ein, falls das so vorgegeben wurde, und legen den Namen auf <b>cmdOK <\/b>oder <b>cmdCancel <\/b>fest.<\/p>\n<p>Dann nutzen wir nochmals die Funktion <b>TwipsFromFonts<\/b>. Diesmal wollen wir damit die Breite des Textes f&uuml;r die Schaltfl&auml;che <b>cmdOK <\/b>oder <b>cmdCancel <\/b>ermitteln, um die Breite der Schaltfl&auml;che entsprechend einstellen zu k&ouml;nnen.<\/p>\n<p>Da die Schaltfl&auml;chen nebeneinander von links nach rechts angeordnet werden sollen, erh&ouml;hen wir den Wert von <b>lngLeft<\/b>, den wir wieder an die aufrufende Routine zur&uuml;ckgeben. So kann diese den Wert f&uuml;r das Anlegen weiterer Schaltfl&auml;chen &uuml;bergeben.<\/p>\n<p>Schlie&szlig;lich rufen wir die Prozedur <b>AddButtonEvent <\/b>auf. Diese legt den Code, den wir im Feld <b>OKCode <\/b>oder <b>CancelCode <\/b>hinterlegt haben, f&uuml;r die soeben angelegte Schaltfl&auml;che an.<\/p>\n<h2>Anlegen der Prozedur f&uuml;r eine Schaltfl&auml;che<\/h2>\n<p>Diese beschreiben wir hier in aller K&uuml;rze: Die Prozedur <b>AddButtonEvent <\/b>nimmt Verweise auf das Formular, das Steuerelement und den einzuf&uuml;genden Code entgegen (siehe Listing 8).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AddButtonEvent(frm<span style=\"color:blue;\"> As <\/span>Form, cmd<span style=\"color:blue;\"> As <\/span>CommandButton, strCode<span style=\"color:blue;\"> As String<\/span>)\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>lngEventProc<span style=\"color:blue;\"> As Long<\/span>\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      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(cmd.Name & \"_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\", cmd.Name)\r\n          lngEventProc = lngEventProc + 1\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 einer Ereignisprozedur f&uuml;r eine Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Sie pr&uuml;ft, ob das Formular bereits ein Klassenmodul enth&auml;lt. Falls nicht, f&uuml;gt sie eines durch Einstellen von <b>HasModule <\/b>auf <b>True <\/b>hinzu. Dann legt sie die Eigenschaft <b>Beim Klicken <\/b>der mit <b>cmd <\/b>&uuml;bergebenen Schaltfl&auml;che auf <b>[Ereignisprozedur] <\/b>fest. Mit der Funktion <b>GetCurrentVBProject <\/b>ermittelt sie das aktuelle VBA-Projekt. Das ist notwendig, da wir die Formulare aus einem Access-Add-In heraus anlegen wollen, wodurch mindestens zwei VBA-Projekte im VBA-Editor ge&ouml;ffnet sind.<\/p>\n<p>Diese Funktion arbeitet mit einem kleinen Trick: Sie durchl&auml;uft alle VBA-Projekte und vergleicht den Pfad des Projekts mit dem Pfad der aktuell ge&ouml;ffneten Datenbank. Sind beide gleich, haben wir das VBA-Projekt der aktuell ge&ouml;ffneten Datenbank, deren Schaltfl&auml;chen manipuliert werden sollen, gefunden und geben den Verweis zur&uuml;ck:<\/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      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<p>Nachdem wir das aktuelle VBA-Projekt ermittelt und mit der Variablen <b>objVBProject <\/b>referenziert haben, referenzieren wir das darin enthaltene Klassenmodul des zu bearbeitenden Formulars mit <b>objVBComponent<\/b>.<\/p>\n<p>Danach pr&uuml;fen wir mit der Funktion <b>ExistsProc<\/b>, ob bereits eine <b>Beim Klicken<\/b>-Prozedur f&uuml;r die betroffene Schaltfl&auml;che vorhanden ist. Sie nimmt den Namen der Prozedur und einen Verweis auf die VB-Komponente entgegen, referenziert das <b>CodeModule<\/b>-Objekt der VB-Komponente und sucht nach einer Zeile, in der sich der Name der gesuchten Prozedur befindet.<\/p>\n<p>Wird diese gefunden, liefert die Funktion den Wert <b>True <\/b>zur&uuml;ck, anderenfalls den Wert <b>False<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ExistsProc(strProcname<span style=\"color:blue;\"> As String<\/span>, _\r\n         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>Wenn noch keine <b>Beim Klicken<\/b>-Prozedur f&uuml;r diese Schaltfl&auml;che vorhanden ist, legen wir diese mit der <b>CreateEventProc<\/b>-Methode an, l&ouml;schen die leere Zeile innerhalb der neuen Prozedur und f&uuml;gen den Text aus <b>strCode <\/b>ein.<\/p>\n<h2>Funktion zum Anlegen von Kontrollk&auml;stchen<\/h2>\n<p>Damit kommen wir zu den Funktionen zum Anlegen der &uuml;brigen Steuerelemente, die an die Felder der Datensatzquelle des Formulars gebunden sind. Wir beginnen mit der Funktion <b>AddCheckBox <\/b>aus Listing 9.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddCheckBox(rstForm<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstControls<span style=\"color:blue;\"> As <\/span>DAO.Recordset, strFormName<span style=\"color:blue;\"> As String<\/span>, _\r\n         lngSection<span style=\"color:blue;\"> As <\/span>AcSection, lngLabelWidth<span style=\"color:blue;\"> As Long<\/span>, lngTop<span style=\"color:blue;\"> As Long<\/span>, lngMaxWidth<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>lbl<span style=\"color:blue;\"> As <\/span>Label\r\n     <span style=\"color:blue;\">Set<\/span> ctl = CreateControl(strFormName, acCheckBox, lngSection, , rstControls!FieldName, _\r\n         lngLabelWidth + 2 * rstForm!Margin, lngTop + 50, rstControls!FieldWidth, rstControls!Fieldheight)\r\n     <span style=\"color:blue;\">Set<\/span> lbl = CreateControl(strFormName, acLabel, lngSection, ctl.Name, , rstForm!Margin, lngTop, _\r\n         lngLabelWidth, rstControls!Fieldheight)\r\n     lbl.Caption = rstControls!Fieldlabel & \":\"\r\n     <span style=\"color:blue;\">If <\/span>ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width &gt; lngMaxWidth<span style=\"color:blue;\"> Then<\/span>\r\n         lngMaxWidth = ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> AddCheckBox = ctl\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Anlegen einer CheckBox<\/span><\/b><\/p>\n<p>Sie nimmt Verweise auf die Recordsets mit den Formular- und den Steuerelementdaten entgegen sowie den Formularnamen, den Zielbereich, die Breite der Beschriftungen und den Abstand zum oberen Rand des Formulars.<\/p>\n<p>Sie erstellt das neue Kontrollk&auml;stchen mit der <b>CreateControl<\/b>-Funktion, der wir diesmal als zweiten Parameter den Wert <b>acCheckBox <\/b>zum Anlegen eines Kontrollk&auml;stchens &uuml;bergeben. Neben den &uuml;blichen Eigenschaften legen wir hier auch den Wert f&uuml;r den Steuerelementinhalt fest, und zwar auf den Namen des Feldes aus der Datensatzquelle des Formulars.<\/p>\n<p>Zus&auml;tzlich legen wir das Bezeichnungsfeld f&uuml;r das Kontrollk&auml;stchen an. Dies geschieht wiederum mit der Funktion <b>CreateControl<\/b>, diesmal mit dem Typ <b>acLabel<\/b>.<\/p>\n<p>Anschlie&szlig;end stellen wir noch die Beschriftung des Bezeichnungsfeldes ein und geben den Verweis auf das neu erstellte Steuerelement an die aufrufende Routine zur&uuml;ck.<\/p>\n<h2>Funktion zum Anlegen von Textfeldern<\/h2>\n<p>Das Anlegen von Textfeldern erfolgt ganz &auml;hnlich wie das der Kontrollk&auml;stchen. Die dazu verwendete Funktion <b>AddTextBox <\/b>sehen wir in Listing 10.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddTextBox(rstForm<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstControls<span style=\"color:blue;\"> As <\/span>DAO.Recordset, strFormName<span style=\"color:blue;\"> As String<\/span>, _\r\n         lngSection<span style=\"color:blue;\"> As <\/span>AcSection, lngLabelWidth<span style=\"color:blue;\"> As Long<\/span>, lngTop<span style=\"color:blue;\"> As Long<\/span>, lngMaxWidth<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>lbl<span style=\"color:blue;\"> As <\/span>Label\r\n     <span style=\"color:blue;\">Set<\/span> ctl = CreateControl(strFormName, acTextBox, lngSection, , rstControls!FieldName, _\r\n         lngLabelWidth + 2 * rstForm!Margin, lngTop, rstControls!FieldWidth, rstControls!Fieldheight)\r\n     <span style=\"color:blue;\">Set<\/span> lbl = CreateControl(strFormName, acLabel, lngSection, ctl.Name, , rstForm!Margin, lngTop, lngLabelWidth, _\r\n         rstControls!Fieldheight)\r\n     lbl.Caption = rstControls!Fieldlabel & \":\"\r\n     <span style=\"color:blue;\">If <\/span>ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width &gt; lngMaxWidth<span style=\"color:blue;\"> Then<\/span>\r\n         lngMaxWidth = ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> AddTextBox = ctl\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Anlegen einer TextBox<\/span><\/b><\/p>\n<h2>Funktion zum Anlegen von Kombinationsfeldern<\/h2>\n<p>Beim Kombinationsfeld gibt es einige zus&auml;tzliche Einstellungen, die wir gegen&uuml;ber dem Kontrollk&auml;stchen und dem Textfeld vornehmen m&uuml;ssen (siehe Listing 11). Alle ben&ouml;tigten Einstellungen befinden sich jedoch im &uuml;bergebenen Recordset mit den Daten aus der Tabelle <b>tblDetailFields <\/b>f&uuml;r das aktuelle Steuerelement. Das Anlegen des <b>ComboBox<\/b>-Steuerelements und des dazugeh&ouml;rigen Bezeichnungsfeldes entsprechen bis auf den Steuerelementtyp <b>acComboBox <\/b>den zuvor beschriebenen Vorgehensweisen. Danach stellen wir jedoch einige zus&auml;tzliche Eigenschaften ein, die speziell der Anzeige der auszuw&auml;hlenden Daten des Kombinationsfeldes entsprechen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AddComboBox(rstForm<span style=\"color:blue;\"> As <\/span>DAO.Recordset, rstControls<span style=\"color:blue;\"> As <\/span>DAO.Recordset, strFormName<span style=\"color:blue;\"> As String<\/span>, _\r\n         lngSection<span style=\"color:blue;\"> As <\/span>AcSection, lngLabelWidth<span style=\"color:blue;\"> As Long<\/span>, lngTop<span style=\"color:blue;\"> As Long<\/span>, lngMaxWidth<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>ctl<span style=\"color:blue;\"> As <\/span>Control\r\n     <span style=\"color:blue;\">Dim <\/span>lbl<span style=\"color:blue;\"> As <\/span>Label\r\n     <span style=\"color:blue;\">Set<\/span> ctl = CreateControl(strFormName, acComboBox, lngSection, , rstControls!FieldName, _\r\n         lngLabelWidth + 2 * rstForm!Margin, lngTop, rstControls!FieldWidth, rstControls!Fieldheight)\r\n     <span style=\"color:blue;\">Set<\/span> lbl = CreateControl(strFormName, acLabel, lngSection, ctl.Name, , rstForm!Margin, lngTop, lngLabelWidth, _\r\n         rstControls!Fieldheight)\r\n     lbl.Caption = rstControls!Fieldlabel & \":\"\r\n     <span style=\"color:blue;\">With<\/span> ctl\r\n         .BoundColumn = rstControls!BoundColumn\r\n         .ColumnCount = rstControls!ColumnCount\r\n         .ColumnWidths = rstControls!ColumnWidths\r\n         .RowSource = rstControls!RowSource\r\n         .RowSourceType = rstControls!RowSourceType\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     <span style=\"color:blue;\">If <\/span>ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width &gt; lngMaxWidth<span style=\"color:blue;\"> Then<\/span>\r\n         lngMaxWidth = ctl.<span style=\"color:blue;\">Left<\/span> + ctl.Width\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> AddComboBox = ctl\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 11: Anlegen einer ComboBox<\/span><\/b><\/p>\n<h2>Funktion zum Kopieren von Icons in die Zieldatenbank<\/h2>\n<p>Fehlt noch die Funktion, welche die Icons, die wir in der Add-In-Datenbank zur Auswahl zur Verf&uuml;gung stellen, in die Tabelle <b>MSysResources<\/b> der Zieldatenbank kopiert. Diese Funktion hei&szlig;t <b>CopyIcon<\/b> und ist in Listing 12 abgebildet. Sie erwartet die Datensatz-ID des Datensatzes der Tabelle <b>MSysResources <\/b>aus der Add-In-Datenbank als Parameter.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>CopyIcon(lngID<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Boolean<\/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>dbc<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;\">Dim <\/span>rstData<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstc<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>rstDataC<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strName<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rstc = db.OpenRecordset(\"SELECT * FROM MSysResources WHERE Id = \" & lngID, dbOpenDynaset)\r\n     strName = rstc!Name\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM MSysResources WHERE name = ''\" & strName & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span>rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         rst.Add<span style=\"color:blue;\">New<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> rstData = rst.Fields(\"Data\").Value\r\n         <span style=\"color:blue;\">Set<\/span> rstDataC = rstc.Fields(\"Data\").Value\r\n         rstData.Add<span style=\"color:blue;\">New<\/span>\r\n         rstData!FileData = rstDataC!FileData\r\n         rstData!FileName = rstDataC!FileName\r\n         rstData.Update\r\n         rst!Extension = rstc!Extension\r\n         rst!Name = rstc!Name\r\n         rst!Type = rstc!Type\r\n         rst.Update\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     CopyIcon = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 12: Kopieren von Icons aus der Add-In-Datenbank in die Zieldatenbank<\/span><\/b><\/p>\n<p>Diese Id w&auml;hlen wir zuvor &uuml;ber eines der Kombinationsfelder <b>cboOKButtonIcon <\/b>oder <b>cboCancelButtonIcon <\/b>aus, welche die in der Tabelle <b>MSysResources <\/b>der Add-In-Datenbank enthaltenen Bilder zur Auswahl anbieten.<\/p>\n<p>In dieser Funktion definieren wir zwei <b>Database<\/b>-Variablen &#8211; eine f&uuml;r die Add-In-Datenbank (<b>dbc<\/b>) und eine f&uuml;r die Datenbank, die das Add-In aufruft (<b>db<\/b>). Au&szlig;erdem deklarieren wir zwei Recordsets, die jeweils die Tabelle <b>MSysResources <\/b>der Add-In-Datenbank und der Host-Datenbank aufnehmen (<b>rstc <\/b>und <b>rst<\/b>). Um die in diesen Tabellen enthaltenen Icons kopieren zu k&ouml;nnen, ben&ouml;tigen wir au&szlig;erdem noch jeweils ein weiteres Recordset, mit dem wir auf die im Anlagefeld enthaltenen Tabellen zugreifen k&ouml;nnen. Diese nennen wir <b>rstData <\/b>und <b>rstDataC<\/b>.<\/p>\n<p>Die Variable <b>rstc <\/b>f&uuml;llen wir mit einem Recordset, dass den Datensatz der Tabelle <b>MSysResources <\/b>der Add-In-Datenbank enth&auml;lt, dessen Feld <b>Id <\/b>dem mit <b>lngID <\/b>gelieferten Prim&auml;rsch&uuml;sselwert entspricht. Hier entnehmen wir gleich den Inhalt des Feldes <b>Name <\/b>und speichern diesen in <b>strName<\/b>.<\/p>\n<p>Dann &ouml;ffnen wir mit <b>rst <\/b>ein Recordset auf Basis der Tabelle <b>MSysResources<\/b>, deren Feld <b>name <\/b>den Wert aus <b>strName <\/b>enth&auml;lt. Wir pr&uuml;fen damit, ob es bereits einen Datensatz in der Tabelle <b>MSysResources <\/b>gibt, dessen Feld <b>name <\/b>den Namen der zu kopierenden Bilddatei enth&auml;lt. Ist das Recordset danach leer, wollen wir die Bilddatei kopieren. Dazu legen wir einen neuen Datensatz im Recordset <b>rst <\/b>an, also in der Tabelle <b>MSysResources <\/b>der aufrufenden Datenbank.<\/p>\n<p>Dann referenzieren wir mit <b>rstData <\/b>das Anlagefeld <b>Data <\/b>der Tabelle <b>MSysResources <\/b>der Host-Datenbank und mit <b>rstDataC <\/b>die entsprechende Tabelle der Add-In-Datenbank. In <b>rstData<\/b> legen wir einen neuen Datensatz an und kopieren die Inhalte der Felder <b>FileData <\/b>und <b>FileName <\/b>aus der Add-In-Datenbank dort hinein. Nach dem Aktualisieren des Datensatzes des Anlagefeldes &uuml;bertragen wir noch die Felder <b>Extension<\/b>, <b>Name <\/b>und <b>Type <\/b>aus der Tabelle <b>MSysResources <\/b>des Add-Ins in die Host-Datenbank und speichern auch diesen Datensatz.<\/p>\n<h2>Tool per Add-In-Men&uuml; und als Formular-Assistent verf&uuml;gbar machen<\/h2>\n<p>Das Add-In wollen wir auf zwei Arten f&uuml;r den Benutzer verf&uuml;gbar machen. Die erste ist die Anzeige in der Liste der Men&uuml;-Add-Ins, die zweite ist der Dialog <b>Neues Formular<\/b>, den wir im Ribbon &uuml;ber den Befehl <b>Erstellen|Formulare|Formularassistent <\/b>&ouml;ffnen.<\/p>\n<p>Dazu f&uuml;gen wir der Add-In-Datenbank die Tabelle <b>USysRegInfo <\/b>hinzu, die in unserem Fall die Daten aus Bild 9 enth&auml;lt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_004.png\" alt=\"Die Tabelle mit den Daten f&uuml;r die Registrierung des Add-Ins\" width=\"700\" height=\"247,9017\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Die Tabelle mit den Daten f&uuml;r die Registrierung des Add-Ins<\/span><\/b><\/p>\n<p>Die oberen vier Datens&auml;tze f&uuml;gen bei der Installation des Add-Ins die Eintr&auml;ge f&uuml;r die Anzeige als Men&uuml;-Add-In zur Registry hinzu.<\/p>\n<p>Hier legen wir fest, dass die Funktion Autostart beim Aufrufen des Add-Ins &uuml;ber das Add-In-Men&uuml; aufgerufen werden soll und wo die Add-In-Datei liegt. Der Platzhalter <b>|ACCDIR <\/b>wird dabei durch das Add-In-Verzeichnis des jeweiligen Rechners ersetzt.<\/p>\n<p>Die Eintr&auml;ge, die im Feld <b>Subkey <\/b>den Wert <b>HKEY_CURRENT_ACCESS_PROFILE\\Wizards\\Form Wizards\\amvDetailformBuilder <\/b>enthalten, legen die Eigenschaften f&uuml;r unsere Add-In-Datenbank als Formular-Assistent fest.<\/p>\n<p>Hier geben wir mit <b>Datasource Required <\/b>und dem Wert <b>1 <\/b>an, dass beim Aufruf des Assistenten die aktuell markierte Tabelle oder Abfrage verwendet werden soll. Mit <b>Function <\/b>legen wir fest, welche Prozedur beim Aufrufen des Assistenten gestartet werden soll, in diesem Fall <b>StartWizard<\/b>. Unter <b>Library <\/b>geben wir wie beim Men&uuml;-Add-In an, wo sich die Datei mit dem Assistenten befindet.<\/p>\n<h2>Routinen zum Starten des Add-Ins<\/h2>\n<p>Die beiden in der Tabelle <b>USysRegInfo <\/b>angegebenen Routinen haben wir im Modul <b>mdlAddIn <\/b>hinterlegt. Beginnen wir mit der einfacheren Variante &#8211; dem Aufruf &uuml;ber das Add-In-Men&uuml;. Die dadurch aufgerufene Funktion <b>Autostart <\/b>sieht wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>Autostart()\r\n     DoCmd.OpenForm \"frmDetailforms\"\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Sie ruft einfach nur das Formular <b>frmDetailforms <\/b>auf, mit dem der Benutzer ein neues Formular anlegen kann.<\/p>\n<p>Die Funktion <b>StartWizard <\/b>statten wir mit einem zus&auml;tzlichen Parameter namens <b>strRecordSource <\/b>aus (siehe Listing 13). F&uuml;r diesen liefert Access beim Aufruf automatisch den Namen der aktuell ausgew&auml;hlten Tabelle oder Abfrage. Die Funktion &ouml;ffnet ein Recordset auf Basis der Tabelle <b>tblDetailforms <\/b>der Add-In-Datenbank, in der das Feld <b>DataSource <\/b>den mit dem Parameter <b>strRecordSource <\/b>gelieferten Tabellen- oder Abfragenamen enth&auml;lt.<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>StartWizard(strRecordSource<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Variant<\/span>\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> rst = CodeDb.OpenRecordset(\"SELECT * FROM tblDetailforms WHERE Datasource = ''\" & strRecordSource & \"''\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         DoCmd.OpenForm \"frmDetailforms\", DataMode:=acFormEdit, WhereCondition:=\"DetailformID = \" & rst!DetailformID\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         DoCmd.OpenForm \"frmDetailforms\", DataMode:=acFormAdd, OpenArgs:=strRecordSource\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 13: Aufruf des Add-Ins als Formular-Assistent<\/span><\/b><\/p>\n<p>Ist ein solcher Datensatz vorhanden, ruft die Funktion das Formular <b>frmDetailforms <\/b>in dem Datenmodus zum Bearbeiten des Datensatzes auf und &uuml;bergibt als Bedingung einen Ausdruck, der den Wert des Prim&auml;rschl&uuml;ssels auf den zuvor ermittelten Datensatz einstellt.<\/p>\n<p>Wurde in der Tabelle <b>tblDetailforms <\/b>kein Datensatz f&uuml;r die angegebene Tabelle oder Abfrage gefunden, &ouml;ffnet die Funktion das Formular frmDetailforms im Modus zum Anlegen eines neuen Datensatzes und &uuml;bergibt mit dem &Ouml;ffnungsargument den Namen der aktuell markierten Tabelle oder Abfrage.<\/p>\n<p>Die Prozedur, die beim Laden des Formulars <b>frmDetailforms <\/b>aufgerufen wird, erg&auml;nzen wir noch um die Anweisungen, die das &Ouml;ffnungsargument verarbeitet, wenn f&uuml;r die angegebene Tabelle oder Abfrage noch kein Detailformular definiert worden sein sollte:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     ...\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(Nz(Me.OpenArgs, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cboDatasource = Me.OpenArgs\r\n         cboDatasource_AfterUpdate\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dabei pr&uuml;ft die Prozedur, ob das &Ouml;ffnungsargument &uuml;berhaupt &uuml;bergeben wurde. Falls ja, stellt sie das Kombinationsfeld <b>cboDataSource <\/b>auf den Namen der &uuml;bergebenen Tabelle oder Abfrage ein und ruft anschlie&szlig;end die Prozedur <b>cboDatasource_AfterUpdate <\/b>auf.<\/p>\n<p>Dadurch werden die Felder der ausgew&auml;hlten Tabelle oder Abfrage in das Unterformular eingetragen. Au&szlig;erdem wird der Tabellen- oder Abfragename als Basis f&uuml;r neue Werte in den Textfeldern <b>txtFormname <\/b>und <b>txtFormTitle <\/b>verwendet.<\/p>\n<h2>Add-In-Eigenschaften<\/h2>\n<p>Damit das Add-In im Add-In-Manager wie gew&uuml;nscht angezeigt wird, stellen wir noch einige Eigenschaften f&uuml;r die Datenbank ein (siehe Bild 10).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_005.png\" alt=\"Eigenschaften der Datenbank\" width=\"424,5589\" height=\"458,6841\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Eigenschaften der Datenbank<\/span><\/b><\/p>\n<p>Au&szlig;erdem benennen wir die Datei so um, dass der Name dem in der Tabelle <b>USysRegInfo <\/b>angegebenen Namen entspricht.<\/p>\n<h2>Installieren des Add-Ins<\/h2>\n<p>Das Add-In installieren wir wie &uuml;blich &uuml;ber den Add-In-Manager, den wir &uuml;ber den Ribbon-Befehl <b>Datenbanktools|Add-Ins|Add-In-Manager <\/b>&ouml;ffnen.<\/p>\n<h2>Ausprobieren des Add-Ins<\/h2>\n<p>Danach ist das Add-In im Men&uuml; <b>Datenbanktools|Add-Ins|Add-Ins <\/b>verf&uuml;gbar und kann gestartet werden, ohne das eine Tabelle oder Abfrage vorausgew&auml;hlt wird. Der Benutzer kann dann mit einer neuen, leeren Detailformular-Konfiguration starten.<\/p>\n<p>Spannender ist jedoch der Aufruf als Formular-Assistent. Hier selektieren wir die Tabelle oder Abfrage, f&uuml;r die wir ein neues Detailformular erstellen wollen. Dann w&auml;hlen wir den Men&uuml;befehl <b>Erstellen|Formulare|Formular-Assistent <\/b>aus, was den Dialog <b>Neues Formular <\/b>&ouml;ffnet. Hier ist die gew&auml;hlte Tabelle bereits ausgew&auml;hlt und wir brauchen nur noch auf den Eintrag <b>amvDetailformBuilder<\/b> zu klicken (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2024_02\/pic_1490_006.png\" alt=\"Add-In als Formular-Assistent &ouml;ffnen\" width=\"674,559\" height=\"406,2772\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Add-In als Formular-Assistent &ouml;ffnen<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag erl&auml;utert, wie man ein Add-In erstellt, mit dem man auf Basis einer Tabelle oder Abfrage ein neues Detailformular erstellen kann. Dieses Formular enth&auml;lt alle Felder der Tabelle oder Abfrage, die daf&uuml;r ausgew&auml;hlt wurden sowie bis zu zwei Schaltfl&auml;chen, die zum Speichern oder Verwerfen der Eingabe verwendet werden k&ouml;nnen.<\/p>\n<p>Wir haben der Beispielanwendung noch einige Elemente hinzugef&uuml;gt, mit denen f&uuml;r neue Datens&auml;tze Standardwerte vorgegeben werden. Diese finden Sie in der Prozedur <b>Form_Load<\/b>.<\/p>\n<p>Man k&ouml;nnte dies noch anpassen, indem man festlegt, dass die zuletzt verwendeten Werte als Standardwert entweder in einer weiteren Tabelle oder in der Registry gespeichert werden.<\/p>\n<p>Im aktuellen Zustand zeigt das Formular <b>frmDetailforms <\/b>immer alle Datens&auml;tze an. Wenn Sie das Add-In mit verschiedenen Datenbanken nutzen, werden also auch immer die Konfigurationen f&uuml;r die jeweils anderen Datenbanken geliefert.<\/p>\n<p>Hier w&auml;re noch ein Filter zu integrieren, der nur die Datens&auml;tze anzeigt, die im Kontext der aktuell ge&ouml;ffneten Datenbank erzeugt wurden. Dabei w&auml;re die Frage, woran man die Datenbank erkennt &#8211; man k&ouml;nnte den Datenbanknamen verwenden, aber auch dieser kann ge&auml;ndert werden und dann w&uuml;rde man die zu dieser Datenbank geh&ouml;renden Elemente nicht mehr finden.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>amvDetailformBuilder.accda<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/B26E0DEE-632F-412F-AF1C-3E67A32488BD\/aiu_1490.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bei der Arbeit mit Microsoft Access gibt es immer wiederkehrende Aufgaben &#8211; zum Beispiel das Anlegen von Detailformularen. Diese sollen die Daten aus einfachen Tabellen darstellen und zwei Schaltfl&auml;chen namens OK und Abbrechen bereitstellen. So kann der Benutzer neue oder ge&auml;nderte Datens&auml;tze &uuml;bernehmen oder diese verwerfen. Dazu sind immer wieder viele kleine Handgriffe n&ouml;tig. Damit dies ab jetzt schneller geht, schauen wir uns an, wie wir die meisten der Schritte automatisieren k&ouml;nnen. Dazu bauen wir ein Formular, mit dem wir alle Konfigurationsschritte erledigen k&ouml;nnen &#8211; von der Auswahl der Datenquelle &uuml;ber die Benennung des Formulars bis hin zur Erstellung des vollst&auml;ndigen Formulars inklusive Code.<\/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":[66022024,662024,44000027],"tags":[],"class_list":["post-55001490","post","type-post","status-publish","format-standard","hentry","category-66022024","category-662024","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>Detailformular per Mausklick erstellen - 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\/Detailformular_mit_Daten_per_Mausklick_erstellen\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Detailformular per Mausklick erstellen\" \/>\n<meta property=\"og:description\" content=\"Bei der Arbeit mit Microsoft Access gibt es immer wiederkehrende Aufgaben - zum Beispiel das Anlegen von Detailformularen. Diese sollen die Daten aus einfachen Tabellen darstellen und zwei Schaltfl&auml;chen namens OK und Abbrechen bereitstellen. So kann der Benutzer neue oder ge&auml;nderte Datens&auml;tze &uuml;bernehmen oder diese verwerfen. Dazu sind immer wieder viele kleine Handgriffe n&ouml;tig. Damit dies ab jetzt schneller geht, schauen wir uns an, wie wir die meisten der Schritte automatisieren k&ouml;nnen. Dazu bauen wir ein Formular, mit dem wir alle Konfigurationsschritte erledigen k&ouml;nnen - von der Auswahl der Datenquelle &uuml;ber die Benennung des Formulars bis hin zur Erstellung des vollst&auml;ndigen Formulars inklusive Code.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-29T18:51:14+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d\" \/>\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=\"39\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Detailformular per Mausklick erstellen\",\"datePublished\":\"2024-02-29T18:51:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/\"},\"wordCount\":5904,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/42b6ddde8c774a37b5c629c31d6c946d\",\"articleSection\":[\"2\\\/2024\",\"2024\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/\",\"name\":\"Detailformular per Mausklick erstellen - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/42b6ddde8c774a37b5c629c31d6c946d\",\"datePublished\":\"2024-02-29T18:51:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/42b6ddde8c774a37b5c629c31d6c946d\",\"contentUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/42b6ddde8c774a37b5c629c31d6c946d\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Detailformular_mit_Daten_per_Mausklick_erstellen\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Detailformular mit Daten per Mausklick erstellen\"}]},{\"@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":"Detailformular per Mausklick erstellen - 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\/Detailformular_mit_Daten_per_Mausklick_erstellen\/","og_locale":"de_DE","og_type":"article","og_title":"Detailformular per Mausklick erstellen","og_description":"Bei der Arbeit mit Microsoft Access gibt es immer wiederkehrende Aufgaben - zum Beispiel das Anlegen von Detailformularen. Diese sollen die Daten aus einfachen Tabellen darstellen und zwei Schaltfl&auml;chen namens OK und Abbrechen bereitstellen. So kann der Benutzer neue oder ge&auml;nderte Datens&auml;tze &uuml;bernehmen oder diese verwerfen. Dazu sind immer wieder viele kleine Handgriffe n&ouml;tig. Damit dies ab jetzt schneller geht, schauen wir uns an, wie wir die meisten der Schritte automatisieren k&ouml;nnen. Dazu bauen wir ein Formular, mit dem wir alle Konfigurationsschritte erledigen k&ouml;nnen - von der Auswahl der Datenquelle &uuml;ber die Benennung des Formulars bis hin zur Erstellung des vollst&auml;ndigen Formulars inklusive Code.","og_url":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/","og_site_name":"Access im Unternehmen","article_published_time":"2024-02-29T18:51:14+00:00","og_image":[{"url":"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"39\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Detailformular per Mausklick erstellen","datePublished":"2024-02-29T18:51:14+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/"},"wordCount":5904,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d","articleSection":["2\/2024","2024","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/","url":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/","name":"Detailformular per Mausklick erstellen - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#primaryimage"},"thumbnailUrl":"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d","datePublished":"2024-02-29T18:51:14+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#primaryimage","url":"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d","contentUrl":"http:\/\/vg02.met.vgwort.de\/na\/42b6ddde8c774a37b5c629c31d6c946d"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Detailformular_mit_Daten_per_Mausklick_erstellen\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Detailformular mit Daten per Mausklick erstellen"}]},{"@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\/55001490","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=55001490"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001490\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001490"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001490"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001490"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}