{"id":55000424,"date":"2024-04-01T00:00:00","date_gmt":"2024-04-23T13:11:59","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=424"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Wozu_mit_Klassen_programmieren","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Wozu_mit_Klassen_programmieren\/","title":{"rendered":"Wozu mit Klassen programmieren?"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/db49a9e75f0e48e4b1dbc8456da955a0\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wer die Office-Anwendungen Access, Excel, Outlook, PowerPoint oder Word mit VBA programmiert, kann eine Menge erreichen, ohne jemals eine eigene Klasse zu programmieren. Wer sich die gesamten M&ouml;glichkeiten er&ouml;ffnen will, kommt jedoch irgendwann nicht mehr um die Programmierung benutzerdefinierter Klassen herum. Dieser Artikel zeigt verschiedene Szenarien auf, wann man benutzerdefinierte Klassen programmieren und darauf basierende Objekte instanziieren kann und soll. Dabei geht es um Begriffe wie Eigenschaften, Methoden, Ereignisse und darum, wo und wie man Klassen einsetzt.<\/b><\/p>\n<p>Wer in den VBA-Projekten von Outlook oder von Dokumenten auf Basis von Access, Excel, PowerPoint oder Word programmiert, ahnt es vielleicht manchmal nicht, aber tats&auml;chlich programmiert man fast zwangsl&auml;ufig innerhalb von Klassenmodulen. Das Modul <b>Projekt1<\/b>, das angezeigt wird, wenn man das VBA-Projekt von Outlook &ouml;ffnet, das Modul <b>ThisDocument <\/b>in Word, die Module <b>DieseArbeitsmappe <\/b>oder <b>Tabelle1 <\/b>in Excel oder auch die Module, die man in Access beim Anlegen von Ereignisprozeduren f&uuml;r Formulare, Steuerelemente oder Berichte verwendet, sind allesamt Klassenmodule.<\/p>\n<p>Diese sind jedoch mit der jeweiligen Anwendung (Outlook) beziehungsweise mit dem jeweiligen Dokument oder dem Element verkn&uuml;pft, in deren Kontext sie ge&ouml;ffnet werden. Dadurch ergeben sich einige Vorteil: Wir k&ouml;nnen n&auml;mlich in diesen direkt auf einige Elemente des jeweiligen Objekts zugreifen. Im Klassenmodul <b>ThisOutlookSession <\/b>von Outlook greifen wir beispielsweise direkt auf die Eigenschaften, Methoden und Ereignisse des <b>Application<\/b>-Objekts zu.<\/p>\n<p>Im Klassenmodul eines Access-Formulars greifen wir direkt auf die Eigenschaften, Methoden und Ereignisse des jeweiligen Formulars und der enthaltenen Steuerelemente zu. Im Klassenmodul <b>ThisDocument <\/b>eines Word-Dokuments stehen die entsprechenden Elemente des <b>Document<\/b>-Objekts zur Verf&uuml;gung und in Excel k&ouml;nnen wir in der Klasse <b>DieseArbeitsmappe <\/b>&uuml;ber die Variable <b>Workbook <\/b>auf die enthaltenen Eigenschaften, Methoden und Ereignisse zugreifen sowie in den Klassen f&uuml;r die einzelnen Tabellen auf das jeweilige <b>Worksheet<\/b>-Element.<\/p>\n<p>Wenn wir bereits eine solche Vielfalt von eingebauten Elementen haben, warum sollten wir noch benutzerdefinierte Klassen entwickeln? Dazu gibt es verschiedene Gr&uuml;nde, die wir in den folgenden Abschnitten beschreiben. Au&szlig;erdem sehen wir uns an, warum es in diesem F&auml;llen ein Klassenmodul sein muss und warum es nicht reicht, ein Standardmodul zu verwenden.<\/p>\n<h2>Grund f&uuml;r Klassen: Eigenschaften, Methoden und Ereignisse zusammenfassen<\/h2>\n<p>Ein wichtiger Anwendungszweck f&uuml;r Klassen ist schlicht und einfach das Zusammenfassen von Elementen in einer Code-Einheit. Wann immer wir im Code allein Informationen zusammenstellen, die zusammengeh&ouml;ren, k&ouml;nnen wir dies mit einer Klasse erledigen.<\/p>\n<p>F&uuml;r diese legen wir dann Eigenschaften fest, mit denen wir die Informationen erfassen k&ouml;nnen. Sobald wir ein Objekt auf Basis der Klasse erstellt haben, k&ouml;nnen wir diesem Informationen &uuml;ber die Eigenschaften zuweisen und die Eigenschaften wieder auslesen. Wir k&ouml;nnen auch daf&uuml;r sorgen, dass das Objekt seine Eigenschaften selbst f&uuml;llt &#8211; beispielsweise durch das Einlesen eines Datensatzes einer Access-Tabelle, der Daten einer E-Mail oder der Abs&auml;tze eines Word-Dokuments.<\/p>\n<p>Auf Basis dieser Eigenschaften k&ouml;nnen wir nun Methoden bereitstellen, welche die Inhalte der Eigenschaften verarbeiten &#8211; beispielsweise, um aus Daten wie Absender, Empf&auml;nger, Betreff und Inhalt eine Outlook-E-Mail zu erstellen und diese abzusenden. Oder wir bieten Funktionen an, welche die eingegebenen Eigenschaften in unterschiedlichen Arten verarbeiten.<\/p>\n<p>So k&ouml;nnen wir beispielsweise einer Klasse, die eine Adresse in Form der Eigenschaften Firma, Anrede, Vorname, Nachname, Stra&szlig;e, PLZ, Ort und Land aufnimmt, eine Funktion hinzuf&uuml;gen, welche aus diesen Informationen einen Adressblock erstellt, den wir in einem Access-Bericht oder in einem Word-Dokument ausgeben k&ouml;nnen.<\/p>\n<p>Ein Beispiel hierf&uuml;r stellen wir im Artikel <b>Klassen programmieren unter VBA <\/b>(<b>www.vbentwickler.de\/423<\/b>) vor.<\/p>\n<h2>Grund f&uuml;r Klassen: Ereignisse bereitstellen<\/h2>\n<p>Wenn Du selbst Ereignisse bereitstellen m&ouml;chtest, die ausgel&ouml;st werden, wenn bestimmte Dinge in Deinem Code geschehen, sind Klassenmodule die einzige M&ouml;glichkeit. &Uuml;ber ein solches Ereignis kannst Du eine Ereignisprozedur implementieren, also eine Prozedur, die mit dem Feuern des Ereignisses gestartet wird und Deinen benutzerdefinierten Code ausf&uuml;hrt.<\/p>\n<p>Nun stellst Du Dir vielleicht die Frage, warum Du nicht direkt dort den auszuf&uuml;hrenden Code unterbringen sollst, wo die ausl&ouml;sende Aktion in Deinem Code geschieht. Der Grund ist, dass Du in einer Klasse allgemeine Elemente und Methoden unterbringst, die f&uuml;r jeden Anwendungsfall gleich sein sollen. Es gibt jedoch auch Anteile, die je nach Anwendungsfall unterschiedlich behandelt werden sollen.<\/p>\n<p>Ein gutes Beispiel daf&uuml;r ist eine Schaltfl&auml;che. Diese erledigt beim Anklicken bereits automatisch Aufgaben &#8211; zum Beispiel &auml;ndert sie ihre Ansicht in den gedr&uuml;ckten Zustand. Du m&ouml;chtest aber f&uuml;r jede Schaltfl&auml;che individuelle Funktionen programmieren. So soll zum Beispiel eine <b>OK<\/b>-Schaltfl&auml;che in einem Formular andere Aktionen ausf&uuml;hren als beispielsweise eine <b>Abbrechen<\/b>-Schaltfl&auml;che. Deshalb stellt die Schaltfl&auml;chen-Klasse f&uuml;r jede einzelne Instanz einer Schaltfl&auml;che eine eigene Ereignisprozedur bereit, in der Du die jeweiligen Anweisungen unterbringen kannst.<\/p>\n<p>Wenn Du selbst eine Klasse programmierst, wird es f&uuml;r Ereignisse ebenfalls zwei Arten von Aktionen geben:<\/p>\n<ul>\n<li>solche, die immer ausgef&uuml;hrt werden sollen und<\/li>\n<li>solche, die individuell implementiert werden sollen, um die Klasse an den jeweiligen Anwendungsfall anzupassen.<\/li>\n<\/ul>\n<h2>Beispiel: Klasse zum Einlesen von XML-Dokumenten<\/h2>\n<p>Nehmen wir an, Du hast eine Klasse programmiert, die das Einlesen von XML-Dateien erledigt. Die Klasse nimmt mit einer Eigenschaft namens <b>Pfad <\/b>den Pfad der einzulesenden XML-Datei entgegen. Eine Methode namens <b>Einlesen<\/b> f&uuml;hrt den Einlesevorgang der XML-Datei in ein Objekt des Typs <b>DOMDocument <\/b>durch. Der Inhalt des XML-Dokuments wird dann durch die Eigenschaft <b>XML <\/b>nach au&szlig;en bereitgestellt. Beim Einlesen kann es vorkommen, dass ein Fehler ausgel&ouml;st wird &#8211; beispielsweise, weil das Dokument einen Syntaxfehler enth&auml;lt. Du k&ouml;nntest nun in der Methode <b>Einlesen<\/b> f&uuml;r den Fall eines Fehlers einfach eine Meldung ausgeben. Wenn Du diese Klasse dann in einem anderen Kontext nutzt, wo Du vielleicht keine Meldung erhalten m&ouml;chtest, sondern den Fehler in einer Protokolldatei erfassen willst, musst Du den Code der Klasse &auml;ndern. Damit hast Du dann verschiedene Versionen einer Klasse in Deinen Anwendungen.<\/p>\n<p>Besser w&auml;re es, wenn Du in der XML-Klasse eine Schnittstelle anbieten w&uuml;rdest, mit der das aufrufende Element abfragen k&ouml;nnte, ob und wann ein Fehler auftritt. Dazu gibt es zwei M&ouml;glichkeiten: Du k&ouml;nntest einen eventuellen Fehler mit einem Parameter der Methode <b>Einlesen <\/b>zur&uuml;ckgeben. Wir k&ouml;nnten aber auch ein Ereignis beispielsweise namens <b>Fehler <\/b>in der XML-Klasse definieren, das beim Eintreten eines Fehlers ausgel&ouml;st wird und das die Fehlermeldung als Parameter bereitstellt. Auf die Ausgabe einer Meldung beim Auftreten eines Fehlers innerhalb der XML-Klasse verzichten wir nun nat&uuml;rlich.<\/p>\n<p>Damit k&ouml;nntest Du nun im aufrufenden Element, also beispielsweise im Klassenmodul eines Access-Formulars, das Ereignis implementieren, das beim Einlesefehler ausgel&ouml;st wird. Und egal, von wo Du die Klasse nutzt &#8211; Du kannst in der Ereignisprozedur immer auf die gew&uuml;nschte Weise auf den aufgetretenen Fehler reagieren.<\/p>\n<p>Auf die Programmierung von Ereignissen in Klassen gehen wir im Artikel <b>Ereignisse in Klassen programmieren <\/b>(<b>www.vbentwickler.de\/425<\/b>) genauer ein.<\/p>\n<h2>Grund f&uuml;r Klassen: Mehrere Instanzen m&ouml;glich<\/h2>\n<p>Wenn Du nicht gerade Ereignisse deklarieren und implementieren m&ouml;chtest, k&ouml;nnte man argumentieren, dass ein Standardmodul f&uuml;r einige Anwendungszwecke ausreicht, f&uuml;r die man sonst ein Klassenmodul definieren w&uuml;rde. Wir k&ouml;nnen auch im Standardmodul Eigenschaften und Methoden definieren, die wir dann nutzen.<\/p>\n<p>Was ein Standardmodul allerdings nicht bietet, ist die Erstellung mehrerer Instanzen. Wenn wir also beispielsweise mit der oben erw&auml;hnten XML-Klasse mehrere XML-Dokumente laden und ihren Inhalt abrufbar halten wollten, k&ouml;nnten wir dies mit einem Standardmodul nicht realisieren. Die darin enthaltene Variable zum Speichern des Inhalts des XML-Dokuments w&uuml;rde bei jedem Einlesen einer weiteren XML-Datei &uuml;berschrieben werden.<\/p>\n<p>In diesem Fall k&ouml;nnen wir ein Klassenmodul besser nutzen, weil wir davon ohne Probleme mehrere Instanzen nutzen k&ouml;nnen. Dazu ben&ouml;tigen wir schlicht mehrere Objektvariablen, die wir dann mit Instanzen der XML-Klasse f&uuml;llen.<\/p>\n<p>Wir k&ouml;nnen dann f&uuml;r jede Objektvariable die <b>Einlesen<\/b>-Methode aufrufen und f&uuml;r jede Objektvariable separat auf den in der XML-Eigenschaft gespeicherten Inhalt des XML-Dokuments zugreifen.<\/p>\n<h2>Beliebig viele Instanzen in Collection speichern<\/h2>\n<p>Wenn wir Instanzen einer Klasse erstellen und diese jeweils in zuvor deklarierten Objektvariablen speichern, ist die Anzahl der Instanzen durch die Anzahl der Objektvariablen begrenzt. Dies ist jedoch in vielen F&auml;llen nicht praktikabel.<\/p>\n<p>Wenn wir beispielsweise f&uuml;r alle Textfelder in einem Access-Formular jeweils eine Instanz einer Klasse erstellen wollen, welche bestimmte Ereignisse von Textfeldern kapselt, wollen wir nicht auf gut Gl&uuml;ck eine bestimmte Menge von Variablen f&uuml;r diese Instanzen deklarieren. Stattdessen deklarieren wir jeweils eine Variable f&uuml;r die Instanz eines Textfeldes und speichern diese nach dem Instanziieren in einer Collection. Danach k&ouml;nnen wir mit der gleichen Variable eine neue Instanz erstellen und auch diese zur Collection hinzuf&uuml;gen.<\/p>\n<p>Der erste Vorteil ist, dass wir so beliebig viele Instanzen erstellen k&ouml;nnen und nicht durch die Anzahl der vorbereiteten Objektvariablen eingeschr&auml;nkt werden.<\/p>\n<p>Ein weiterer Vorteil ist, dass wir die Instanzen, falls notwendig, in einer Schleife &uuml;ber alle Elemente der Collection durchlaufen k&ouml;nnen.<\/p>\n<h2>Grund f&uuml;r Klassen: Wiederverwendbarkeit<\/h2>\n<p>Es gibt sicherlich Klassen, die speziell f&uuml;r eine Anwendung programmiert werden und die nur dort sinnvoll einsetzbar sind. In vielen F&auml;llen k&ouml;nnen wir jedoch Code in Klassen organisieren, die wir in vielen verschiedenen Anwendungen nutzen k&ouml;nnen.<\/p>\n<p>Wenn wir die Klasse in einer Anwendung erfolgreich eingesetzt haben, kopieren wir diese einfach in die n&auml;chste Anwendung und nutzen sie dort. Die Klasse zum Einlesen von XML-Dokumenten und zum Ausgeben des enthaltenen XML-Codes w&auml;re ein solches Beispiel.<\/p>\n<h2>Grund f&uuml;r Klassen: Ereignisse anderer Objekte implementieren<\/h2>\n<p>Ein essenzieller Grund, um ein Klassenmodul zu verwenden, ist das Implementieren von Ereignissen anderer Objekte. Wenn wir das Ereignis <b>Fehler <\/b>der oben vorgestellten XML-Klasse implementieren wollen, um im Fehlerfall beim Einlesen eine Fehlermeldung in eine Protokolldatei zu schreiben, k&ouml;nnen wir dies nur innerhalb eines weiteren Klassenmoduls erledigen.<\/p>\n<p>Dabei spielt es allerdings keine Rolle, ob wir die Objektvariable in einem eingebauten Klassenmodul anlegen und die Ereignisprozedur dort implementieren oder ob wir das in einem benutzerdefinierten Klassenmodul erledigen.<\/p>\n<p>Wenn sich die M&ouml;glichkeit ergibt, ist es immer leichter, das in einem eingebauten Klassenmodul wie beispielsweise dem eines Access-Formulars, eines Word-Dokuments oder einer Excel-Arbeitsmappe zu erledigen, denn dann brauchen wir dazu nicht noch eine benutzerdefinierte Klasse zu programmieren und zu instanziieren.<\/p>\n<h2>Beispiel f&uuml;r das Implementieren von Ereignissen anderer Objekte<\/h2>\n<p>Wir k&ouml;nnen nicht nur die Ereignisse von Objekten auf Basis von benutzerdefinierten Klassen implementieren. Auch die eingebauten Klassen stellen Ereignisse zur Verf&uuml;gung. Dabei unterscheiden wir zwischen zwei Arten:<\/p>\n<ul>\n<li>Eingebaute Klassen, die zu den sichtbaren Objekten von Anwendungen geh&ouml;ren &#8211; also solche von Access-Formularen oder -Berichten, von Word-Dokumenten, von Excel-Arbeitsmappen oder -Arbeitsbl&auml;ttern oder auch die Klasse <b>ThisOutlookSession<\/b>, die automatisch beim Verwenden von Outlook zur Verf&uuml;gung steht.<\/li>\n<li>Eingebaute Klassen, die man erst noch referenzieren muss und die nicht automatisch ein Klassenmodul bereitstellen wie zum Beispiel Datensatzgruppen (<b>Recordset<\/b>) in Access, <b>Application <\/b>in Word, Bereiche (<b>Range<\/b>) in Excel oder E-Mails (<b>MailItem<\/b>) in Outlook.<\/li>\n<\/ul>\n<p>Wir deklarieren also in einem Klassenmodul, ganz gleich, ob es sich nun um ein eingebautes oder ein benutzerdefiniertes Klassenmodul handelt, eine Objektvariable f&uuml;r das Element, dessen Ereignisse wir implementieren wollen.<\/p>\n<p>Dazu m&uuml;ssen wir ein spezielles Schl&uuml;sselwort namens <b>WithEvents <\/b>benutzen. Damit wir nicht versehentlich eine Klasse mit diesem Schl&uuml;sselwort deklarieren, die gar keine Ereignisse anbietet, liefert IntelliSense nur solche Eintr&auml;ge, die auch Ereignisse enthalten.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>In diesem Artikel haben wir uns die Gr&uuml;nde angesehen, die f&uuml;r den Einsatz von benutzerdefinierten Klassenmodulen sprechen.<\/p>\n<p>In weiteren Artikeln, auf die wir im Laufe dieses Artikels verwiesen haben, f&uuml;llen wir die theoretischen Ans&auml;tze dieses Artikels mit Leben. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wer die Office-Anwendungen Access, Excel, Outlook, PowerPoint oder Word mit VBA programmiert, kann eine Menge erreichen, ohne jemals eine eigene Klasse zu programmieren. Wer sich die gesamten M&ouml;glichkeiten er&ouml;ffnen will, kommt jedoch irgendwann nicht mehr um die Programmierung benutzerdefinierter Klassen herum. Dieser Artikel zeigt verschiedene Szenarien auf, wann man benutzerdefinierte Klassen programmieren und darauf basierende Objekte instanziieren kann und soll. Dabei geht es um Begriffe wie Eigenschaften, Methoden, Ereignisse und darum, wo und wie man Klassen einsetzt.<\/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,44000025],"tags":[],"yst_prominent_words":[],"class_list":["post-55000424","post","type-post","status-publish","format-standard","hentry","category-66022024","category-662024","category-VBAProgrammierung"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000424","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000424"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000424\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000424"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}