{"id":55001383,"date":"2022-10-01T00:00:00","date_gmt":"2022-10-03T14:37:07","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1383"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Rechnungsverwaltung_Kundendetails","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/","title":{"rendered":"Rechnungsverwaltung: Kundendetails"},"content":{"rendered":"<p><b>Eine Rechnungsverwaltung, mit der Rechnungen an verschiedene Kunden geschickt werden sollen, ben&ouml;tigt eine Tabelle zum Speichern diese Kunden. Logisch, dass wir dieser Tabelle auch ein Formular zum komfortablen Bearbeiten der Kunden an die Seite stellen. Dieses enth&auml;lt allerdings nicht nur die reinen Kundendaten, sondern wir wollen damit auch noch die Bestellungen des jeweiligen Kunden in einem Unterformular anzeigen &#8211; und dar&uuml;ber die Anzeige der Bestelldetails zu erm&ouml;glichen.<\/b><\/p>\n<h2>Unterformular sfmKundeDetails f&uuml;r die Bestellungen<\/h2>\n<p>Wir beginnen direkt mit dem Entwurf des Unterformulars zur Anzeige der Bestellungen des Kunden. Dieses wollen wir <b>sfmKundeDetails <\/b>nennen. Diesem f&uuml;gen wir &uuml;ber die Eigenschaft <b>Datensatzquelle <\/b>gleich die Tabelle <b>tblBestellungen <\/b>hinzu.<\/p>\n<p>Im Gegensatz zum Unterformular aus dem Beitrag <b>Rechnungsverwaltung: Bestell&uuml;bersicht <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>), wo wir alle Bestellungen inklusive der Angabe des jeweiligen Kunden in einem Unterformular darstellen, ben&ouml;tigen wir hier nicht mehr die Anzeige des Kunden &#8211; dieser wird ja schon im Hauptformular angezeigt, das wir gleich noch erstellen werden. Also f&uuml;gen wir nun die Felder <b>Bestellnummer<\/b>, <b>RechnungAm<\/b>, <b>Zahlungsziel<\/b>, <b>BezahltAm <\/b>und <b>StorniertAm <\/b>zum Detailbereich des Formularentwurfs hinzu.<\/p>\n<p>Dieser sieht anschlie&szlig;end wie in Bild 1 aus. Damit die Daten in der Datenblattansicht angezeigt werden, legen wir die Eigenschaft <b>Standardansicht <\/b>dort auf den Wert <b>Datenblatt <\/b>fest. Au&szlig;erdem wollen wir, dass der Kunde die Daten in diesem Unterformular nicht direkt bearbeiten kann. Daher legen wir die Eigenschaften <b>Anf&uuml;gen zulassen<\/b>, <b>L&ouml;schen zulassen <\/b>und <b>Bearbeitungen zulassen <\/b>jeweils auf den Wert <b>Nein <\/b>ein. Damit k&ouml;nnen wir die Arbeiten an diesem Formular vorerst beenden und dieses schlie&szlig;en.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_001.png\" alt=\"Entwurf des Unterformulars sfmKundeDetails\" width=\"599,559\" height=\"329,3351\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Entwurf des Unterformulars sfmKundeDetails<\/span><\/b><\/p>\n<h2>Hauptformular frmKundeDetails anlegen<\/h2>\n<p>Danach legen wir ein weiteres Formular namens <b>frmKundeDetails <\/b>an. Bevor wir diesem das Unterformular <b>sfmKundeDetails <\/b>hinzuf&uuml;gen, m&uuml;ssen wir die Datensatzquelle f&uuml;r das Hauptformular festlegen. So kann Access direkt erkennen, dass es zwischen den Datensatzquellen von Haupt- und Unterformular eine Beziehung gibt und dies entsprechend in den Eigenschaften <b>Verkn&uuml;pfen von <\/b>und <b>Verkn&uuml;pfen nach <\/b>des Unterformular-Steuerelements vermerken.<\/p>\n<p>Wenn wir schon die Datensatzquelle definiert haben, k&ouml;nnen wir auch direkt die gew&uuml;nschten Felder aus der Feldliste in den Detailbereich des Formulars ziehen. Dabei ber&uuml;cksichtigen wir alle Felder mit Ausnahme des Feldes <b>ID<\/b>, das nur zu Verkn&uuml;pfungszwecken gepflegt wird und f&uuml;r den Benutzer unsichtbar bleiben soll (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_002.png\" alt=\"Entwurf des Hauptformulars frmKundeDetails\" width=\"499,5589\" height=\"372,5946\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Entwurf des Hauptformulars frmKundeDetails<\/span><\/b><\/p>\n<p>Falls Sie sich wundern, dass in unserem Formular beispielsweise f&uuml;r das Feld <b>AnredeID <\/b>ein Beschriftungsfeld mit dem Text <b>Anrede <\/b>angelegt wurde: Wir haben direkt im Tabellenentwurf die f&uuml;r die Bezeichnungsfelder gew&uuml;nschten Texte f&uuml;r die Eigenschaft <b>Beschriftung <\/b>der jeweiligen Felder hinterlegt. Mehr dazu erfahren Sie im Beitrag <b>Bezeichnungsfelder im Griff <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>).<\/p>\n<h2>Unterformular zum Hauptformular hinzuf&uuml;gen<\/h2>\n<p>Danach teilen wir die Felder auf zwei Spalten auf, sodass wir unten das Unterformular <b>sfmKundeDetails <\/b>platzieren k&ouml;nnen. Dieses ziehen wir aus dem Navigationsbereich in den Formularentwurf und erhalten nach wenigen Anpassungen das Ergebnis aus Bild 3. Zu diesen Anpassungen geh&ouml;rt neben der Ausrichtung und der Einstellung der Gr&ouml;&szlig;e das Festlegen der Eigenschaften <b>Horizontaler Anker <\/b>und <b>Vertikaler Anker <\/b>jeweils auf den Wert <b>Beide<\/b>. Damit wird das Unterformular mit dem Hauptformular vergr&ouml;&szlig;ert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_003.png\" alt=\"Das Hauptformular frmKundeDetails mit dem Unterformular\" width=\"599,559\" height=\"416,6974\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Das Hauptformular frmKundeDetails mit dem Unterformular<\/span><\/b><\/p>\n<p>Gegebenenfalls k&ouml;nnen Sie sich nun noch davon &uuml;berzeugen, dass Access automatisch das Prim&auml;rschl&uuml;sselfeld <b>ID <\/b>der Tabelle <b>tblKunden <\/b>f&uuml;r die Eigenschaft <b>Verkn&uuml;pfen nach <\/b>und das Fremdschl&uuml;sselfeld <b>KundeID <\/b>der Tabelle <b>tblBestellungen <\/b>f&uuml;r die Eigenschaft <b>Verkn&uuml;pfen von <\/b>eingetragen hat. Dies stellt sicher, dass das Unterformular immer nur die Datens&auml;tze der Tabelle <b>tblBestellungen <\/b>anzeigt, die mit dem Datensatz der Tabelle <b>tblKunden <\/b>aus dem Hauptformlar verkn&uuml;pft sind.<\/p>\n<p>Da wir bereits einige Beispieldatens&auml;tze angelegt haben, wie im Beitrag <b>Rechnungsverwaltung: Beispieldaten <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>) beschrieben, finden wir beim Wechsel in die Formularansicht bereits einige Beispieldaten vor (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_004.png\" alt=\"Ein Kunde und seine Bestellungen\" width=\"574,559\" height=\"421,3995\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Ein Kunde und seine Bestellungen<\/span><\/b><\/p>\n<h2>Validierung im Hauptformular<\/h2>\n<p>Damit k&ouml;nnen wir uns nun um die Validierung der Eingabefelder im Hauptformular k&uuml;mmern. Hier sind Einschr&auml;nkungen bei folgenden Feldern n&ouml;tig:<\/p>\n<ul>\n<li><b>Anrede<\/b>: Pflichtfeld<\/li>\n<li><b>Vorname<\/b>, <b>Nachname<\/b>, <b>Stra&szlig;e<\/b>, <b>Ort<\/b>, <b>Land<\/b>: Pflichtfelder<\/li>\n<li><b>PLZ<\/b>: Ausgehend von der vereinfachenden Annahme, wir h&auml;tten es mit Adressen aus dem Bereich Deutschland, &Ouml;sterreich und der Schweiz zu tun, muss diese f&uuml;nf Stellen (f&uuml;r Deutschland) oder vier Stellen (f&uuml;r &Ouml;sterreich und Schweiz) aufweisen.<\/li>\n<li><b>E-Mail<\/b>: Diese soll grob validiert werden, also auf ein enthaltenes @-Zeichen und einen Punkt.<\/li>\n<li><b>Ust-IDNr.<\/b>: Soll f&uuml;r Deutschland und &Ouml;sterreich gepr&uuml;ft werden auf <b>DE<\/b> plus neun Ziffern beziehungsweise auf <b>ATU <\/b>plus acht Ziffern, f&uuml;r Schweiz muss das Feld leer sein.<\/li>\n<\/ul>\n<p>Da Pflichtfelder nur beim Speichern des kompletten Datensatzes gepr&uuml;ft werden k&ouml;nnen und dies f&uuml;r die abh&auml;ngigen Felder ohnehin der Fall ist, k&ouml;nnen wir uns hier auf das Ereignis <b>Vor Aktualisierung <\/b>des Formulars konzentrieren.<\/p>\n<p>F&uuml;r dieses hinterlegen wir die Prozedur aus Listing 1. Das Ereignis wird nur beim Versuch ausgel&ouml;st, den Datensatz nach vorherigen &Auml;nderungen zu speichern &#8211; also etwa beim Wechsel zu einem anderen Datensatz oder beim Speichern mit der Tastenkombination <b>Strg + S<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtKundennummer, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine Kundennummer ein.\", vbOKOnly + vbExclamation, \"Kundennummer fehlt\"\r\n         Me!txtKundennummer.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>Nz(Me!cboAnredeID, 0) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte w&auml;hlen Sie eine Anrede aus.\", vbOKOnly + vbExclamation, \"Anredefehlt\"\r\n         Me!cboAnredeID.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtVorname, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen Vornamen ein.\", vbOKOnly + vbExclamation, \"Vorname fehlt\"\r\n         Me!txtVorname.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtStrasse, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine Stra&szlig;e ein.\", vbOKOnly + vbExclamation, \"Stra&szlig;e fehlt\"\r\n         Me!txtStrasse.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtPLZ, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine PLZ ein.\", vbOKOnly + vbExclamation, \"PLZ fehlt\"\r\n         Me!txtPLZ.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtOrt, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie einen Ort ein.\", vbOKOnly + vbExclamation, \"Ort fehlt\"\r\n         Me!txtOrt.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!cboLand, 0)) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"W&auml;hlenSie ein Land aus.\", vbOKOnly + vbExclamation, \"Land fehlt\"\r\n         Me!cboLand.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Nz(Me!txtEMail, \"\")) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Bitte geben Sie eine E-Mail-Adresse ein.\", vbOKOnly + vbExclamation, \"E-Mail-Adresse fehlt\"\r\n         Me!txtEMail.SetFocus\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Exit Sub<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Validieren beim Speichern des Datensatzes<\/span><\/b><\/p>\n<p>Vorab die Information, dass wir alle gebundenen Steuerelemente mit Pr&auml;fixen versehen haben, in diesem Fall die Textfelder mit <b>txt <\/b>und die Kombinationsfelder mit <b>cbo<\/b>. Auf diese Weise kann man sauber zwischen den Feldnamen der Datensatzquelle und den daran gebundenen Steuerelementen unterscheiden.<\/p>\n<p>Diese Prozedur enth&auml;lt einige <b>If&#8230;Then<\/b>-Bedingungen, die jeweils eine &Uuml;berpr&uuml;fung f&uuml;r ein Feld vornehmen. Die erste untersucht beispielsweise, ob das Feld <b>txtFirma <\/b>leer ist. Ist das der Fall, erscheint eine entsprechende Meldung, der Fokus wird auf das Textfeld eingestellt und der R&uuml;ckgabeparameter <b>Cancel <\/b>auf den Wert <b>True<\/b>.<\/p>\n<p>Au&szlig;erdem verlassen wir an dieser Stelle mit <b>Exit Sub <\/b>die Prozedur. Das Einstellen des Parameters <b>Cancel <\/b>auf <b>True <\/b>sorgt daf&uuml;r, dass der <b>Speichern<\/b>-Vorgang, der das Ereignis <b>Vor Aktualisierung <\/b>ausgel&ouml;st hat, abgebrochen wird.<\/p>\n<h2>Validieren der E-Mail-Adresse<\/h2>\n<p>Die E-Mail-Adresse k&ouml;nnen wir direkt nach der Eingabe validieren und den Benutzer darauf hinweisen, falls die E-Mail-Adresse nicht g&uuml;ltig ist. Deshalb reicht es auch aus, dass wir in der Prozedur Form_BeforeUpdate nur auf eine leere Zeichenkette pr&uuml;fen. Sobald der Benutzer einmal ein Zeichen f&uuml;r die E-Mail eingegeben hat, kann er dieses nur nach Eingabe einer g&uuml;ltigen E-Mail-Adresse verlassen.<\/p>\n<p>Wie Sie die G&uuml;ltigkeit einer E-Mail-Adresse &uuml;berpr&uuml;fen, haben wir im Beitrag <b>E-Mail-Adressen validieren per VBA  <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>) beschrieben. Die dortige Funktion <b>CheckEMailSyntax <\/b>verwenden wir auch in diesem Formular, um die E-Mails nach der Eingabe zu pr&uuml;fen. Dazu hinterlegen wir f&uuml;r das Ereignis <b>Vor Aktualisierung <\/b>des Textfelds <b>txtEMail<\/b> die Prozedur aus Listing 2.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtEMail_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strEMail<span style=\"color:blue;\"> As String<\/span>\r\n     strEMail = Nz(Me!txtEMail, \"\")\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> CheckEMailSyntax(strEMail)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die E-Mail-Adresse ''\" & strEMail & \"'' ist nicht g&uuml;ltig.\", vbOKOnly + vbExclamation, \"Ung&uuml;ltige E-Mail\"\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Prozedur zum Pr&uuml;fen von E-Mails direkt nach der Eingabe<\/span><\/b><\/p>\n<p><!--30percent--><\/p>\n<p>Die Prozedur liest den Inhalt des Textfeldes <b>txtEMail <\/b>in die Variable <b>strEMail <\/b>ein. Falls das Feld den Inhalt <b>Null <\/b>hat, landet eine leere Zeichenkette in <b>strEMail<\/b>. Danach ruft die Prozedur die Funktion <b>CheckEMailSyntax <\/b>auf und &uuml;bergibt dieser die E-Mail-Adresse zur Pr&uuml;fung. Ist das Ergebnis nicht <b>True<\/b>, zeigt die Prozedur eine Meldung an. Au&szlig;erdem sorgt das Einstellen des Parameters <b>Cancel <\/b>auf den Wert <b>True <\/b>daf&uuml;r, dass das Feld nicht verlassen werden kann. Das Ergebnis sieht beispielsweise wie in Bild 5 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_005.png\" alt=\"Die E-Mail-Adresse konnte nicht validiert werden.\" width=\"574,559\" height=\"303,0734\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Die E-Mail-Adresse konnte nicht validiert werden.<\/span><\/b><\/p>\n<h2>Postleitzahl validieren<\/h2>\n<p>Das Feld <b>PLZ <\/b>ist ohnehin schon im Datenmodell auf f&uuml;nf Zeichen begrenzt. Das reicht aus, wenn der Benutzer &#8211; wie vorgegeben &#8211; nur die Postleitzahl eingibt und nicht, wie hier und da noch zu sehen, die Postleitzahl mit f&uuml;hrendem L&auml;nderkennzeichen, also beispielsweise <b>D-47137<\/b>. Es sollen also nur Zahlen eingegeben werden. Das Feld <b>PLZ <\/b>ist allerdings mit dem Felddatentyp <b>Kurzer Text <\/b>versehen. Warum das, wenn doch nur Zahlen eingegeben werden k&ouml;nnen sollen? Weil es auch Postleitzahlen mit f&uuml;hrender Null gibt (<b>01234<\/b>) und diese gern wegf&auml;llt, wenn man das Text als Zahlenfeld definiert. Um dennoch daf&uuml;r zu sorgen, dass nur Zahlen eingegeben werden k&ouml;nnen, haben wir zwei M&ouml;glichkeiten. Die erste ist, nach der Eingabe zu pr&uuml;fen, ob der Benutzer nur Zahlen eingegeben hat. Das erledigen wir mit der Ereignisprozedur <b>Vor Aktualisierung <\/b>f&uuml;r das Feld <b>txtPLZ<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtPLZ_BeforeUpdate(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> IsNumeric(Me!txtPLZ)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die PLZ darf nur aus Zahlen bestehen.\",  vbOKCancel + vbExclamation,  \"Ung&uuml;ltige Postleitzahl\"\r\n         Cancel = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dadurch erscheint eine Meldung, wenn der Benutzer andere Zeichen als Zahlen eingibt.<\/p>\n<p>Die Alternative ist, direkt die Eingabe von Zahlen zu unterbinden. Wie das gelingt, zeigen wir im Beitrag <b>Textfeld nur mit bestimmten Zeichen f&uuml;llen <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>).<\/p>\n<p>Wir k&ouml;nnten hier noch einen Schritt weitergehen und die Validierung der Postleitzahl vom angegebenen Land abh&auml;ngig machen. Darauf verzichten wir an dieser Stelle jedoch.<\/p>\n<h2>Das Feld Kundennummer<\/h2>\n<p>Das Feld <b>Kundennummer <\/b>nimmt eine besondere Stellung ein. Es soll in unserem Beispiel eine Kundennummer angeben, die mit <b>99 <\/b>beginnt und danach sechs Ziffern, bestehend aus Nullen und dem Wert des Prim&auml;rschl&uuml;sselfeldes besteht. F&uuml;r den Prim&auml;rschl&uuml;sselwert <b>123 <\/b>also beispielsweise <b>99000123<\/b>. Dieser Wert soll m&ouml;glichst automatisch erzeugt werden, wenn der Benutzer die ersten Daten in den Kundendatensatz eintr&auml;gt. Wie man dies realisieren kann, lernen Sie im Beitrag <b>Nummern f&uuml;r Bestellungen et cetera generieren <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>).<\/p>\n<p>Dort entnehmen wir die folgenden beiden Prozeduren, von denen die erste ausgel&ouml;st wird, wenn der Benutzer irgendein Feld bearbeitet. Dieses pr&uuml;ft, ob es sich um einen neuen, leeren Datensatz handelt und stellt die Eigenschaft <b>TimerInterval <\/b>auf <b>100 <\/b>ein:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Dirty(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span>Me.NewRecord<span style=\"color:blue;\"> Then<\/span>\r\n         Me.TimerInterval = 100\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Dadurch wird das Ereignis <b>Bei Zeitgeber <\/b>100 Millisekunden sp&auml;ter ausgel&ouml;st. Dieses stellt die Kundennummer auf einen Wert ein, welche aus <b>99000000 <\/b>und dem Prim&auml;rschl&uuml;sselwert zusammengesetzt ist. Danach stellt sie die Eigenschaft <b>TimerInterval <\/b>wieder auf <b>0 <\/b>ein, was dazu f&uuml;hrt, dass die Prozedur <b>Form_Timer <\/b>vorerst nicht erneut ausgel&ouml;st wird:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n     Me!txtKundennummer = Format(Me!ID, \"99000000\")\r\n     Me.TimerInterval = 0\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Der Hintergrund ist, dass der Autowert f&uuml;r das Prim&auml;rschl&uuml;sselfeld erst einen Augenblick nach dem Ausl&ouml;sen von <b>Bei Ge&auml;ndert <\/b>gesetzt wird und wir erst dann auf diesen zugreifen k&ouml;nnen, um ihn als Grundlage f&uuml;r die Kundennummer zu verwenden.<\/p>\n<h2>Kundennummer vor Zugriff sch&uuml;tzen<\/h2>\n<p>Wenn wir die Kundennummer wie in diesem Fall beim Anlegen eines neuen Kunden per Code festlegen, sollten wir das irgendwie f&uuml;r den Benutzer kenntlich machen. Anderenfalls denkt er vielleicht, er m&uuml;sse die Kundennummer selbst anlegen.<\/p>\n<p>Die einfachste M&ouml;glichkeit ist, das Feld einfach zu deaktivieren und vor seinem Zugriff zu sch&uuml;tzen. Dazu stellen wir die Eigenschaft <b>Aktiviert <\/b>des Textfeldes <b>txtKundennummer <\/b>auf <b>Nein <\/b>ein. Wir k&ouml;nnen das Feld auch so formatieren, dass der Kunde es gar nicht als editierbar wahrnimmt. Dazu stellen Sie auch noch die Eigenschaft <b>Gesperrt <\/b>auf <b>Ja <\/b>ein.<\/p>\n<p>Damit der Rahmen verschwindet, legen Sie f&uuml;r die Eigenschaft <b>Rahmenart <\/b>den Wert <b>Transparent <\/b>fest. Und schlie&szlig;lich richten wir den Inhalt &uuml;ber den Wert <b>Linksb&uuml;ndig <\/b>f&uuml;r die Eigenschaft <b>Textausrichtung <\/b>noch links aus.<\/p>\n<p>Die Kundennummer wird nun automatisch angelegt, sobald der Benutzer irgendein Feld bearbeitet, und erscheint wie in Bild 6.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_006.png\" alt=\"Automatisches Anlegen der Kundennummer\" width=\"424,5589\" height=\"221,7251\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Automatisches Anlegen der Kundennummer<\/span><\/b><\/p>\n<h2>Unterformular f&uuml;r die Bestellungen mit Funktion f&uuml;llen<\/h2>\n<p>Damit sind die Steuerelemente im Hauptformular vollst&auml;ndig und wir k&ouml;nnen uns dem Unterformular und den damit verbundenen Funktionen zuwenden.<\/p>\n<p>Hier wollen wir die folgenden Funktionen umsetzen:<\/p>\n<ul>\n<li>Schaltfl&auml;che zum Anzeigen der Details zur aktuell markierten Bestellung<\/li>\n<li>Schaltfl&auml;che zum L&ouml;schen der aktuell markierten Bestellung<\/li>\n<li>Schaltfl&auml;che zum Anlegen einer neuen Bestellung f&uuml;r diesen Kunden<\/li>\n<li>Anzeigen der Bestellung per Doppelklick auf die Bestellnummer im Unterformular<\/li>\n<\/ul>\n<h2>Anzeigen der aktuell markierten Bestellung per Schaltfl&auml;che<\/h2>\n<p>Die Schaltfl&auml;che <b>cmdBestellungAnzeigen <\/b>soll die aktuell im Unterformular markierte Bestellung im Formular <b>frmBestellungDetails <\/b>&ouml;ffnen. Dazu hinterlegen wir die Prozedur aus Listing 3. Diese liest die <b>ID <\/b>der aktuell markierten Bestellung aus dem Unterformular in die Variable <b>lngAktuelleBestellungID <\/b>ein. Dann &ouml;ffnet sie das Formular <b>frmBestellungDetails <\/b>als modalen Dialog zum Bearbeiten des Datensatzes, den wir mit dem Parameter <b>WhereCondition <\/b>&uuml;bergeben.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdBestellungAnzeigen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngAktuelleBestellungID<span style=\"color:blue;\"> As Long<\/span>\r\n     lngAktuelleBestellungID = Me!sfmKundeDetails.Form!ID\r\n     DoCmd.OpenForm \"frmBestellungDetails\", WindowMode:=acDialog, DataMode:=acFormEdit, WhereCondition:=\"ID = \" _\r\n         & lngAktuelleBestellungID\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmBestellungDetails\")<span style=\"color:blue;\"> Then<\/span>\r\n         DoCmd.Close acForm, \"frmBestellungDetails\"\r\n         Me!sfmKundeDetails.Form.Refresh\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 3: Prozedur zum Anzeigen der aktuell markierten Bestellung per Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Im Formular <b>frmBestellungDetails <\/b>klickt der Benutzer dann nach dem Betrachten oder Bearbeiten des Datensatzes auf die <b>OK<\/b>-Schaltfl&auml;che, was das Formular unsichtbar macht. Dadurch l&auml;uft der aufrufende Code weiter und schlie&szlig;t das Formular frmBestellungDetails, bevor es mit der <b>Refresh<\/b>-Methode die angezeigten Daten im Unterformular aktualisiert, sodass zwischenzeitlich durchgef&uuml;hrte &Auml;nderungen direkt dort angezeigt werden.<\/p>\n<h2>L&ouml;schen der aktuell markierten Bestellung<\/h2>\n<p>Die zweite Schaltfl&auml;che hei&szlig;t <b>cmdBestellungLoeschen <\/b>und soll die aktuell im Unterformular markierte Bestellung l&ouml;schen. Dazu ruft es die Prozedur aus Listing 4 auf. Die Prozedur ermittelt ebenfalls die <b>ID <\/b>des aktuell markierten Eintrags. Dann versucht sie, den betroffenen Datensatz mit der <b>DELETE<\/b>-Anweisung zu l&ouml;schen &#8211; allerdings bei zuvor deaktivierter eingebauter Fehlerbehandlung. Eventuell tritt bei L&ouml;schen ein Fehler auf, weil es f&uuml;r die Bestellung bereits Bestellpositionen gibt. Dieser Fehler tritt auf, weil wir f&uuml;r die Beziehung zwischen den Tabellen <b>tblBestellungen <\/b>und <b>tblBestellpositionen <\/b>festgelegt haben, dass keine L&ouml;schweitergabe erfolgen darf. <\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdBestellungLoeschen_Click()\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>lngZuLoeschendeBestellungID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     lngZuLoeschendeBestellungID = Me!sfmKundeDetails.Form!ID\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     db.Execute \"DELETE FROM tblBestellungen WHERE ID = \" & lngZuLoeschendeBestellungID, dbFailOnError\r\n     <span style=\"color:blue;\">If <\/span>Err.Number = 3200<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Die Bestellung enth&auml;lt bereits Bestellpositionen. Bitte entfernen Sie diese nach Pr&uuml;fung und \" _\r\n             & \"l&ouml;schen Sie erst dann die Bestellung.\", vbOKOnly + vbInformation, \"L&ouml;schen nicht m&ouml;glich\"\r\n         DoCmd.OpenForm \"frmBestellungDetails\", WindowMode:=acDialog, DataMode:=acFormEdit, WhereCondition:=\"ID = \" _\r\n             & lngZuLoeschendeBestellungID\r\n         <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmBestellungDetails\")<span style=\"color:blue;\"> Then<\/span>\r\n             DoCmd.Close acForm, \"frmBestellungDetails\"\r\n             Me!sfmBestellungenUebersicht.Form.Refresh\r\n             Me!sfmBestellungenUebersicht.Form.Recordset.FindFirst \"ID = \" & lngZuLoeschendeBestellungID\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!sfmKundeDetails.Form.Requery\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Prozedur zum L&ouml;schen der aktuell markierten Bestellung per Schaltfl&auml;che<\/span><\/b><\/p>\n<p>Den gegebenenfalls auftretenden Fehler fangen wir ab, indem wir eine Meldung anzeigen, die den Benutzer darauf hinweist, dass er zuvor die Bestellpositionen manuell l&ouml;schen muss. Dazu &ouml;ffnen wir direkt das Formular <b>frmBestellungDetails <\/b>und zeigen die betroffene Bestellung an. Nachdem der Benutzer die notwendigen Arbeiten durchgef&uuml;hrt hat, schlie&szlig;en wir das Formular und aktualisieren die Anzeige im Unterformular <b>sfmBestellungenUebersicht <\/b>des aufrufenden Formulars.<\/p>\n<p>Hat der Benutzer alle Bestellpositionen gel&ouml;scht, kann er anschlie&szlig;end auch die Bestellung l&ouml;schen, indem er nochmals auf die Schaltfl&auml;che <b>cmdBestellungLoeschen <\/b>klickt.<\/p>\n<h2>Anlegen einer neuen Bestellung<\/h2>\n<p>Zum Anlegen einer neuen Bestellung soll ebenfalls das Formular <b>frmBestellungDetails <\/b>ge&ouml;ffnet werden. Das erledigt die dazu aufgerufene Prozedur <b>cmdNeueBestellung_Click<\/b>, welche das Formular im Modus zum Anlegen eines neuen Datensatzes &ouml;ffnet. Eine &auml;hnliche Funktion haben schon im Beitrag <b>Rechnungsverwaltung: Bestell&uuml;bersicht <\/b>(<b>www.access-im-unternehmen.de\/****<\/b>) zum Formular <b>frmBestellungenUebersicht <\/b>hinzugef&uuml;gt.<\/p>\n<p>Im Gegensatz zur dortigen Prozedur wissen wir hier allerdings schon, f&uuml;r welchen Kunden die Bestellung angelegt werden soll. Das hei&szlig;t, wir k&ouml;nnten diese Information schon an das Formular <b>frmBestellungDetails <\/b>&uuml;bergeben und dort so auswerten, dass der betroffene Kunde bereits im Kombinationsfeld selektiert ist.<\/p>\n<p>Deshalb fragen wir in der Prozedur aus Listing 5 zuvor den Wert des Prim&auml;rschl&uuml;sselfeldes <b>ID <\/b>f&uuml;r den angezeigten Kunden ab und speichern diesen in der Variablen <b>lngKundeID<\/b>. Diesen Wert &uuml;bergeben wir dann als Wert des Parameters <b>OpenArgs<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdNeueBestellung_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>lngNeueBestellungID<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngKundeID<span style=\"color:blue;\"> As Long<\/span>\r\n     lngKundeID = Me!ID\r\n     DoCmd.OpenForm \"frmBestellungDetails\", WindowMode:=acDialog, DataMode:=acFormAdd, OpenArgs:=lngKundeID\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmBestellungDetails\")<span style=\"color:blue;\"> Then<\/span>\r\n         lngNeueBestellungID = Forms!frmBestellungDetails!ID\r\n         DoCmd.Close acForm, \"frmBestellungDetails\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me!sfmKundeDetails.Form.Requery\r\n     Me!sfmKundeDetails.Form.Recordset.FindFirst \"ID = \" & lngNeueBestellungID\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Prozedur zum &Ouml;ffnen des Formulars zum Anlegen einer neuen Bestellung<\/span><\/b><\/p>\n<p>Diesen Wert m&uuml;ssen wir noch im aufgerufenen Formular <b>frmBestellungDetails <\/b>auswerten. Dazu f&uuml;gen wir diesem eine Ereignisprozedur f&uuml;r das Ereignis <b>Beim &Ouml;ffnen <\/b>hinzu, das wie folgt aussieht:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Open(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Nz(Me.OpenArgs, 0) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cboKundeID.DefaultValue = Me.OpenArgs\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Hier pr&uuml;fen wir, ob ein Wert mit dem Parameter <b>OpenArgs <\/b>&uuml;bergeben wurde. Falls ja, k&ouml;nnen wir diesen mit der Eigenschaft <b>OpenArgs <\/b>des Formulars auslesen. Ist das der Fall, stellen wir den Standardwert des Kombinationsfeldes <b>cboKundeID <\/b>auf den &uuml;bergebenen Wert ein. Dies f&uuml;hrt dazu, dass der Kunde, f&uuml;r den die Bestellung angelegt werden soll direkt beim &Ouml;ffnen der leeren Bestellung ausgew&auml;hlt ist (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_007.png\" alt=\"Auswahl eines Kunden\" width=\"549,559\" height=\"293,4223\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Auswahl eines Kunden<\/span><\/b><\/p>\n<p>Nachdem der Benutzer den neuen Datensatz angelegt und das Formular mit einem Klick auf <b>OK <\/b>unsichtbar gemacht hat, ruft die aufrufende Prozedur den Prim&auml;rschl&uuml;sselwert des neuen Datenatzes ab. Dann schlie&szlig;t es das zwar unsichtbare, aber noch ge&ouml;ffnete Formular. Anschlie&szlig;end aktualisiert es das Unterformular und markiert den soeben neu hinzugef&uuml;gten Datensatz mit der <b>FindFirst<\/b>-Methode des <b>Recordset<\/b>-Objekts des Unterformulars.<\/p>\n<h2>Anzeigen der aktuell markierten Bestellung per Doppelklick<\/h2>\n<p>Zum schnelleren Anzeigen der Details zu einer Bestellung f&uuml;gen wir dem Textfeld <b>txtBestellnummer <\/b>des Unterformulars <b>sfmKundeDetails <\/b>das Ereignis <b>Beim Doppelklicken <\/b>hinzu. Dieses ruft das Formular <b>frmBestellungDetails <\/b>auf und &uuml;bergibt die <b>ID <\/b>des anzuzeigenden Datensatzes mit dem Parameter <b>WhereCondition<\/b>. Nachdem der Benutzer das Formular <b>frmBestellungDetails <\/b>mit einem Klick auf <b>OK <\/b>unsichtbar gemacht hat, schlie&szlig;t die Prozedur das Formular und aktualisiert die Daten im Unterformular (siehe Listing 6).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBestellnummer_DblClick(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>lngAktuelleBestellungID<span style=\"color:blue;\"> As Long<\/span>\r\n     lngAktuelleBestellungID = Me!ID\r\n     DoCmd.OpenForm \"frmBestellungDetails\", WindowMode:=acDialog, DataMode:=acFormEdit, WhereCondition:=\"ID = \" _\r\n         & lngAktuelleBestellungID\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmBestellungDetails\")<span style=\"color:blue;\"> Then<\/span>\r\n         DoCmd.Close acForm, \"frmBestellungDetails\"\r\n         Me.Refresh\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 6: Prozedur zum Anzeigen der Bestelldetails per Doppelklick auf die Bestellnummer<\/span><\/b><\/p>\n<h2>Schaltfl&auml;chen zum Bearbeiten und L&ouml;schen nur aktivieren, wenn ein Datensatz im Unterformular markiert ist<\/h2>\n<p>Nun wollen wir noch sicherstellen, dass der Benutzer nur auf die Schaltfl&auml;chen <b>cmdBestellungAnzeigen <\/b>und <b>cmdBestellungLoeschen <\/b>klicken kann, wenn er auch einen Datensatz im Unterformular markiert hat. Das ist zumindest dann der Fall, wenn das Unterformular gerade gar keinen Datensatz anzeigt.<\/p>\n<p>Wir wollen also die Eigenschaft <b>Enabled <\/b>dieser beiden Schaltfl&auml;chen aktivieren, wenn das Unterformular einen Datensatz anzeigt und deaktivieren, wenn das Unterformular leer ist. Die Idee ist nun, dazu das Ereignis <b>Beim Anzeigen <\/b>des Unterformulars zu nutzen und darin zu pr&uuml;fen, ob der Wert des Feldes <b>ID <\/b>im Unterformular gerade <b>Null <\/b>ist (kein Datensatz) oder einen Wert enth&auml;lt (Datensatz markiert). Das Problem dabei ist, dass das <b>Beim Anzeigen<\/b>-Ereignis nur beim Anzeigen eines Datensatzes angezeigt wird. Wenn das Unterformular aber nun leer ist, wird kein Datensatz angezeigt und folglich auch das Ereignis nicht ausgel&ouml;st.<\/p>\n<p>Die n&auml;chste Idee war dann, das Ereignis <b>Beim Anzeigen <\/b>im Hauptformular zu nutzen, um die Schaltfl&auml;chen zu deaktivieren und diese im Ereignis <b>Beim Anzeigen <\/b>des Unterformular nur dann zu aktivieren, wenn dieses einen Datensatz anzeigt. Das Problem hierbei ist allerdings, dass das Ereignis im Unterformular vor dem entsprechenden Ereignis des Hauptformulars ausgel&ouml;st wird (und das auch nur, wenn es &uuml;berhaupt ausgel&ouml;st wird). Und das Ereignis <b>Beim Anzeigen <\/b>wird auch nicht ausgel&ouml;st, wenn der Benutzer einen Datensatz l&ouml;scht &#8211; und damit auch nicht beim L&ouml;schen des letzten Datensatzes.<\/p>\n<p>Wie kommen wir aus diesem Dilemma heraus? Der erste Schritt ist: Wir pr&uuml;fen im Ereignis <b>Beim Anzeigen <\/b>des Hauptformulars, ob das Unterformular aktuell Datens&auml;tze enth&auml;lt, und aktivieren oder deaktivieren in Abh&auml;ngigkeit davon die beiden Schaltfl&auml;chen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Me!sfmKundeDetails.Form.Recordset.RecordCount  = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cmdBestellungAnzeigen.Enabled = <span style=\"color:blue;\">True<\/span>\r\n         Me!cmdBestellungLoeschen.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!cmdBestellungAnzeigen.Enabled = <span style=\"color:blue;\">False<\/span>\r\n         Me!cmdBestellungLoeschen.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit haben wir aber noch nicht den Fall abgedeckt, wenn der Benutzer die letzte Bestellung eines Kunden l&ouml;scht oder einem Kunden die erste Bestellung hinzuf&uuml;gt.<\/p>\n<p>Diese beiden F&auml;lle k&ouml;nnen jedoch von diesem Formular aus nur &uuml;ber die beiden Schaltfl&auml;chen <b>cmdBestellungLoeschen <\/b>oder <b>cmdNeueBestellung <\/b>ausgel&ouml;st werden. Also f&uuml;gen wir beiden <b>Click<\/b>-Ereignissen einfach den Aufruf der oben beschriebenen Prozedur <b>Form_Current <\/b>hinzu:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdBestellungLoeschen_Click()\r\n     ...\r\n     Form_Current\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdNeueBestellung_Click()\r\n     ...\r\n     Form_Current\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Da sp&auml;ter aber einmal noch weitere Anweisungen zur Prozedur <b>Form_Current <\/b>hinzukommen k&ouml;nnten, die nicht jedes Mal ausgef&uuml;hrt werden sollen, wenn der Benutzer eine Bestellung hinzuf&uuml;gt oder entfernt, wollen wir die dortigen Anweisungen noch in eine eigene Prozedur auslagern und die Aufrufe von <b>Form_Current <\/b>zu dieser Prozedur &auml;ndern. Die Prozedur sieht dann wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>RefreshButtons()\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> Me!sfmKundeDetails.Form.Recordset.RecordCount = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Me!cmdBestellungAnzeigen.Enabled = <span style=\"color:blue;\">True<\/span>\r\n         Me!cmdBestellungLoeschen.Enabled = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         Me!cmdBestellungAnzeigen.Enabled = <span style=\"color:blue;\">False<\/span>\r\n         Me!cmdBestellungLoeschen.Enabled = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span> <\/pre>\n<p>Einen Aufruf platzieren wir nun in <b>Form_Current<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     RefreshButtons\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Und zwei weitere Aufrufe der Prozedur <b>RefreshButtons <\/b>landen dort, wo wir zuvor <b>Form_Current <\/b>aufgerufen haben:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdBestellungLoeschen_Click()\r\n     ...\r\n     RefreshButtons\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdNeueBestellung_Click()\r\n     ...\r\n     RefreshButtons\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Feinschliff: OK-Schaltfl&auml;che und Co.<\/h2>\n<p>Auch das Formular <b>frmKundeDetails <\/b>soll eine <b>OK<\/b>-Schaltfl&auml;che zum Schlie&szlig;en des Formulars erhalten. Diese Schaltfl&auml;che, unten links untergebracht, l&ouml;st folgenden Code aus:<\/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>Damit m&uuml;ssen wir bei allen Aufrufen dieses Formulars darauf achten, dass wir es nach dem Auslesen eventuell neu hinzugef&uuml;gter oder ge&auml;nderter Datens&auml;tze von den aufrufenden Prozeduren aus wieder schlie&szlig;en.<\/p>\n<p>Desweiteren m&uuml;ssen wir f&uuml;r die Schaltfl&auml;che <b>cmdOK <\/b>die Eigenschaft <b>Vertikaler Anker <\/b>auf <b>Unten <\/b>einstellen, da es sonst vom Unterformular &uuml;berdeckt wird, wenn der Benutzer das Formular vergr&ouml;&szlig;ert.<\/p>\n<p>Schlie&szlig;lich soll das Formular selbst immer nur einen Datensatz anzeigen und nicht das Bl&auml;ttern in den Kundendatens&auml;tzen erm&ouml;glichen. Daher stellen wir die Eigenschaften <b>Navigationsschaltfl&auml;chen<\/b>, <b>Datensatzmarkierer <\/b>und <b>Bildlaufleisten <\/b>auf <b>Nein <\/b>ein. Die Eigenschaft <b>Automatisch zentrieren <\/b>erh&auml;lt den Wert <b>Ja<\/b>.<\/p>\n<p>Die Titelleiste zeigt aktuell noch den Namen des Formulars an, also <b>frmKundeDetails<\/b>. Dies wollen wir noch &auml;ndern, indem wir den Wert <b>Kundendetails <\/b>f&uuml;r die Eigenschaft <b>Beschriftung <\/b>des Formulars einstellen.<\/p>\n<p>Damit der Benutzer nicht mehr mit der Tabulatortaste vom ersten oder letzten Steuerelement der Aktivierreihenfolge zum vorherigen oder n&auml;chsten Datensatz springen kann, stellen wir die Eigenschaft <b>Zyklus <\/b>auf <b>Aktueller Datensatz <\/b>ein.<\/p>\n<p>Das Formular sieht im aktuellen Zustand nun wie in Bild 8 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2022_05\/pic_1383_008.png\" alt=\"Das fertige Formular\" width=\"649,559\" height=\"463,0952\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Das fertige Formular<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Das Formular zur Anzeige der Kundendetails mitsamt der Bestellungen dieses Kunden erlaubt das einfache Verwalten der enthaltenen Daten. In weiteren Beitr&auml;gen zeigen wir, wie Sie dieses Formular von einer Kunden&uuml;bersicht aus &ouml;ffnen k&ouml;nnen oder auch per Befehl aus dem Ribbon.<\/p>\n<p>Au&szlig;erdem werden wir sp&auml;ter noch eine Schaltfl&auml;che hinzuf&uuml;gen, mit der Sie von diesem Formular aus eine Rechnung f&uuml;r eine Bestellung erstellen und versenden k&ouml;nnen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>Rechnungsbericht_Formulare.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/FF09BF49-F5A6-4038-9030-74A4C57AEEE5\/aiu_1383.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Eine Rechnungsverwaltung, mit der Rechnungen an verschiedene Kunden geschickt werden sollen, ben&ouml;tigt eine Tabelle zum Speichern diese Kunden. Logisch, dass wir dieser Tabelle auch ein Formular zum komfortablen Bearbeiten der Kunden an die Seite stellen. Dieses enth&auml;lt allerdings nicht nur die reinen Kundendaten, sondern wir wollen damit auch noch die Bestellungen des jeweiligen Kunden in einem Unterformular anzeigen &#8211; und dar&uuml;ber die Anzeige der Bestelldetails zu erm&ouml;glichen.<\/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":[662022,66052022,44000023],"tags":[],"class_list":["post-55001383","post","type-post","status-publish","format-standard","hentry","category-662022","category-66052022","category-Mit_Formularen_arbeiten"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Rechnungsverwaltung: Kundendetails - 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\/Rechnungsverwaltung_Kundendetails\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Rechnungsverwaltung: Kundendetails\" \/>\n<meta property=\"og:description\" content=\"Eine Rechnungsverwaltung, mit der Rechnungen an verschiedene Kunden geschickt werden sollen, ben&ouml;tigt eine Tabelle zum Speichern diese Kunden. Logisch, dass wir dieser Tabelle auch ein Formular zum komfortablen Bearbeiten der Kunden an die Seite stellen. Dieses enth&auml;lt allerdings nicht nur die reinen Kundendaten, sondern wir wollen damit auch noch die Bestellungen des jeweiligen Kunden in einem Unterformular anzeigen - und dar&uuml;ber die Anzeige der Bestelldetails zu erm&ouml;glichen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2022-10-03T14:37:07+00:00\" \/>\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=\"21\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Rechnungsverwaltung: Kundendetails\",\"datePublished\":\"2022-10-03T14:37:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/\"},\"wordCount\":3606,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"articleSection\":[\"2022\",\"5\\\/2022\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/\",\"name\":\"Rechnungsverwaltung: Kundendetails - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"datePublished\":\"2022-10-03T14:37:07+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Rechnungsverwaltung_Kundendetails\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Rechnungsverwaltung: Kundendetails\"}]},{\"@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":"Rechnungsverwaltung: Kundendetails - 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\/Rechnungsverwaltung_Kundendetails\/","og_locale":"de_DE","og_type":"article","og_title":"Rechnungsverwaltung: Kundendetails","og_description":"Eine Rechnungsverwaltung, mit der Rechnungen an verschiedene Kunden geschickt werden sollen, ben&ouml;tigt eine Tabelle zum Speichern diese Kunden. Logisch, dass wir dieser Tabelle auch ein Formular zum komfortablen Bearbeiten der Kunden an die Seite stellen. Dieses enth&auml;lt allerdings nicht nur die reinen Kundendaten, sondern wir wollen damit auch noch die Bestellungen des jeweiligen Kunden in einem Unterformular anzeigen - und dar&uuml;ber die Anzeige der Bestelldetails zu erm&ouml;glichen.","og_url":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/","og_site_name":"Access im Unternehmen","article_published_time":"2022-10-03T14:37:07+00:00","author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"21\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Rechnungsverwaltung: Kundendetails","datePublished":"2022-10-03T14:37:07+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/"},"wordCount":3606,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"articleSection":["2022","5\/2022","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/","url":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/","name":"Rechnungsverwaltung: Kundendetails - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"datePublished":"2022-10-03T14:37:07+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Rechnungsverwaltung_Kundendetails\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Rechnungsverwaltung: Kundendetails"}]},{"@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\/55001383","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=55001383"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001383\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}