Berufsbildende Schule Wirtschaft Trier Wirtschaftsgymnasium VBA-Programmierung Objekte von Anfang an Unterrichtsmaterialien von Christoph Oberweis Stand: 21.01.2014 1 Inhalt 1 Modelle der Wirklichkeit 1.1 Anwendungsprogramme und Objektorientierung 1.2 Klassen 1.3 Von der Klasse zu Objekt 2 Implementierung in VBA 3 Module, Klassenmodule und UserForms 4 Die logischen Grundstrukturen 4.1 Algorithmus und Struktogramm 4.2 Sequenz, Abfragen und Schleifen 4.3 Funktionen und Prozeduren (Ergänzungen) 5 Algorithmen mit strukturierten Datentypen 6 VBA und EXCEL Literatur: HELD, B. (2000): EXCEL-VBA-Programmierung.- München, Mark und Technik-Verlag JANKA, A. (2005): VBA mit Word. – Bonn, Galileo Computing - Verlag MARTIN, R. (1999): VBA mit Office 2000 lernen. – Bonn, Addison-Wesley – Verlag MINHORST, A. (2005): Das Access 2003 Entwicklerbuch.- Bonn, Addison-Wesley – Verlag MINHORST, A. (2012): Anwendungen entwickeln mit Access.- Duisburg, André MinhorstVerlag 2 1 Modelle der Wirklichkeit 1.1 Anwendungsprogramme und Objektorientierung Erst durch eine geeignete Software kann der Computer Probleme der realen Welt lösen. Hintergrund einer betriebswirtschaftlich orientierten Software sind letztlich immer Geschäftsprozesse; dies gilt sowohl für Standardsoftware wie z.B. Officepakete als auch für Individualsoftware wie z. B. eine prozessorientierte Auftragsabwicklung eines Produktionsbetriebs. Software bildet einen Ausschnitt der realen Welt in einer Modellwelt ab. Diese Modellwelt ist (im Gegensatz zur realen Welt) auf nur die Notwendigkeiten reduziert, die benötigt werden, um die jeweiligen Probleme der betrieblichen Wirklichkeit mit Hilfe von Computern zu lösen. Modellierung ist der Transfer eines Ausschnittes der realen Welt in ein Modell. Objekte der realen Welt (Kunde, Artikel usw.) und ihre Eigenschaften (Kundennummer, Artikelbezeichnung) werden zu Objekten inkl. ihrer Attribute in der Modellwelt. Der Begriff „Objekt“ ist nun allerdings als Fachbegriff der Informatik zu verstehen. Beispiel: Ein Autohaus der wirklichen Welt, die Autos sind Objekte. Das Foto ist bereits ein Modell! Modell: Idealisierte Darstellung der realen Welt zur Veranschaulichung bestimmter Sachverhalte/Eigenschaften o. Ä. Das Foto zeigt bestimmte Dinge (z. B. aktuelle Trendfarbe, Design) in einem bestimmten Maßstab aus einer bestimmte Perspektive usw.: Ikonisches Modell (bildhaft) 3 Fortschreitende Abstraktion: 23.08.2006, 11:30 Abstraktion: Verzicht auf Details, die Darstellung wird „ungenauer“, jedoch bleiben z. B. Standort und Silhouette der Fahrzeuge weiterhin erkennbar. Allerdings wurden nun Datum und Uhrzeit der Aufnahme hinzugefügt: Mit diesem Modell könnte z. B. dargestellt werden, welche Arten von Kraftfahrzeugen (PKW, LKW, Bus usw.) zu diesem Zeitpunkt an diesem Ort abgestellt waren. Farbinformationen wären dann unwichtig, ebenso Plakate und Fahnen (s. vorheriges Bild). Viele Aspekte der Wirklichkeit werden modelliert: z. B.: Welche Stellplätze sind belegt? Analogmodell: hier eine Lageskizze der Stellplätze, stark vereinfachte Karte, jedes abgestellte Fahrzeug wird zu einem „X“ („Analogie“: Analogmodell, eine noch weitere Abstraktion der Wirklichkeit) 4 Eine vorläufige vereinfachte Aussage, was Modellierung in der Praxis bedeutet: Modellierung ist eine Vorgehensweise, bei der Software-Entwickler versuchen, einen für sie relevanten realen Ausschnitt der wirklichen Welt so zu vereinfachen und „in den Griff zu bekommen“, dass aus dem Ergebnis, dem Modell, möglichst effizient Software entwickelt werden kann. Die Modelle sollen auch Nicht-Informatikern (z. B. Betriebswirten), die allerdings Fachleute für das zu lösende Problem sind, verständlich sein. Dies erleichtert Absprachen hinsichtlich der Lösungen. Zudem sollen sich die Modelle an modernen Paradigmen der Informatik orientieren (objektorientierte GUIs, Inter-netAnwendungen, Schichtenmodelle usw.). Eine weitere Betrachtungsweise: Was haben alle Kfzs gemeinsam? Gemeinsamkeiten: Vier Räder, Lenkrad, Motor, Türen, eine Angabe hinsichtlich der Leistung usw. Die Gemeinsamkeiten können in einer „Schablone“ festgelegt werden. Mit dieser lassen sich dann im Sinne eines Bauplans individuelle Autos mit unterschiedlichen individuellen Merkmalen „erzeugen“. 5 1.2 Klassen Zur Erzeugung individueller Fahrzeuge mithilfe der Schablone werden nun Eigenschaften der Schablone genauer festgelegt: Kfz Hersteller: Text Typ: Text ……… Hubraum: Ganzzahl ……… Farbe: Text ……. Schablone, nach dieser könnten (fast) unendlich viele Fahrzeuge gebaut werden. Allerdings benötigt dieser Plan exakte Angaben zu den Details des Fahrzeugs: Eigenschaften So könnte ein Bauplan formuliert sein: Zahlen und Texte als Informationen zu den Eigenschaften des Fahrzeugs Bei dieser Betrachtungsweise ist nun Folgendes zu beachten: Den Eigenschaften (man spricht auch von Attributen) wie „Hubraum“, „Farbe“ usw. sind in der Schablone noch keine Werte zugeordnet. Sie sind gleichsam Namen für „Platzhalter“ (Variablen) und lediglich danach spezifiziert, welche „Sorte“ (= Typen) von Zeichen später bei den individuell erzeugten Fahrzeugen hier stehen dürfen. Zusammenfassung: 6 Es ist nun erforderlich, der Schablone „etwas mitzugeben“, was gestattet, die Attributswerte der später erzeugten Fahrzeuge zu setzten, zu verändern und zu lesen. Möglicherweise sollen auch sonstige Verarbeitungen mit diesen Werten durchgeführt werden. Natürlich könnte man unabhängig von diesen Schablonen einfach Befehle programmieren, welche eine Veränderung der Attributswerte im Computer durchführt (so hat man das früher gemacht). Aber genau das will die objektorientierte Programmierung verhindern. Dadurch, dass die Datenveränderung an die Schablone gleichsam gekoppelt wird, gewinnt man bei der Modellierung einer Kfz -Verwaltung eine größere Nähe zum Objekt der realen Welt. Alle erlaubten Operationen auf die Attribute einer speziellen Schablone werden in dieser festgelegt und nicht irgendwie von außen beliebig zugelassen. Man spricht hier von Geheimhaltungsprinzip bzw. Kapselung der Daten. Es steht also nicht im Mittelpunkt der Betrachtungsweise: „Wie programmiere ich eine Preiserhöhung mit Plausibilitätsprüfung?“ sondern die Frage: „Was lege ich in meiner Schablone fest, was mit den Daten des individuellen Fahrzeugs später möglich sein soll?“ Werden nun die möglichen Verarbeitungen, (= Methoden) hinsichtlich der Attribute der Schablone hinzugefügt, so spricht man von einer Klasse. Merke: Der Begriff "Schablone" ist umgangssprachlich gemeint und diente nur der Verdeutlichung, während "Klasse" ein Fachbegriff der Informatik ist! Zur Darstellung von Klassen wird häufig UML (Unified Modelling Language) benutzt. „Die Unified Modelling Language ist eine Sprache zur Spezifikation, Visualisierung, Konstruktion und Dokumentation von Modellen für Softwaresysteme, Geschäftsmodelle und andere NichtSoftwaresysteme. Sie bietet den Entwicklern die Möglichkeit, den Entwurf und die Entwicklung von Softwaremodellen auf einheitlicher Basis zu diskutieren.“ Universität Magdeburg (UML-Tutorial) Hinweis: Die Klammern hinter den Methodennamen haben (zunächst vereinfacht ausgedrückt) folgende Bedeutung: Unterhalb der Methodennamen stehen später Programmzeilen, die genau bestimmen, wie was zu tun ist. Mit Hilfe der Klammern hinter „Erfassen“ könnten der Methode dann spezielle Daten übermittelt werden, die für diese Verarbeitung wichtig sind (Schnittstelle). 7 Ein weiterer Hinweis: In manchen Fachdisziplinen werden Modelle dieser Art als Symbolmodelle bezeichnet. Die Namen dieser Methoden deuten inhaltlich darauf hin, dass es bei dieser Modellierung offensichtlich nicht um das Bauen der Fahrzeuge geht (Produktion am Fließband), sondern um ihre Verwaltung beim Autohändler. Die Preisangabe z. B. spielt hinsichtlich der rein technischen Seite der Produktion keine Rolle. Zusammenfassend: Das gleiche Objekt der realen Welt kann völlig unterschiedlich modelliert werden, es kommt darauf an, was man mit dem Modell erreichen will. Hier: Werden Autos gebaut oder werden sie verkauft? Eine Klasse modelliert also ein abstraktes Fahrzeug z. B. aus der rein technischen Sicht oder aus der Sicht von Kaufleuten. Die Attribute und Methoden sind von diesen Sichten abhängig! Aufgabe 1: Entwerfen Sie bitte eine Klasse „Kunde“ (bezogen auf das Autohaus). Legen Sie bitte sinnvolle Attribute und Methoden fest. 8 1.3 Von der Klasse zum Objekt Liegt die Klassenbeschreibung der Fahrzeuge vor, können nun (im Computer) nach ihr alle individuellen Fahrzeuge "erzeugt" werden, welche das Autohaus zu einem bestimmten Zeitpunkt anbietet. Entsprechend der Klassenbeschreibung wird dann aus jedem realen Kfz ein Objekt im Computer. Diese Objekte (man spricht hier auch von Instanzen einer Klasse) besitzen nun ihre individuellen Eigenschaften (Kfz-Nummer, Typ, Leistung, Farbe usw.). Vorgänge mit den realen Fahrzeugen wie "verkauft an Frau X" oder "verkauft von dem Mitarbeiter Herr Y" oder "letzte Inspektion am ZZZZ" können im Computer erfasst und verwaltet werden. :Kfz bedeutet, dass es sich hier um Objekt vom "Typ" der Klasse Kfz handelt (um ein Objekt "Art", wie es in der Klasse Kfz festgelegt wurde). Die Attribute besitzen nun Attributswerte, da die Objekte ja reale Fahrzeuge abbilden. Zur Veranschaulichung eine Analogie: „Rezept“ entspricht „Klasse“, ein bestimmter „Geburtstagskuchen“ für Simone, sie hat am 10.11 Geburtstag, entspricht dem „Objekt“. Mit einem Rezept lassen sich „unendlich“ viele Kuchen backen. Merke: Nicht das Rezept wird gegessen, sondern der Kuchen! Oder: Die individuellen Eigenschaften eines Fahrzeugs werden nicht in der Klasse gespeichert, sondern im Objekt! 9 Hat man die Eigenschaften und Funktionalitäten einer Windows-Maske in einer Klasse festgelegt, lassen sich „unendlich viele“ Masken (quasi auf Knopfdruck) hieraus erzeugen! Eine weitere Veranschaulichung: Hier zeigt jede Explorer-Instanz einen anderen Teil des Dateiverzeichnisses und jede Ansicht kann durch einen Mausklick aktiviert werden. Die Attributwerte der jeweiligen Instanz bleiben solange erhalten, bis sie durch Klick auf den „Schließen-Button“ entfernt wird. 10 2 Implementierung in VBA Nun ist es erforderlich, in die VBA - Programmierumgebung zu wechseln (hier am Beispiel mit VBA unter EXCEL, mit WORD sind die Schritte analog): Bevor nun das Kfz-Beispiel vorgestellt wird, erfolgt zunächst zur Darstellung des Handlings dieser Programmierumgebung ein simples Programmbeispiel ohne Klassen und Objekte: Projektexplorer Eigenschaften der Dialogbox bzw. der Objekte auf ihr 1. Schritt: Excel aufrufen 2. Schritt: Mit <Alt> <F11> in die Programmierumgebung wechseln 3. Schritt: „Diese Arbeitsmappe“ anklicken (Das wird später anders gemacht!) 4. Schritt: Falls jetzt schon Programmcode erscheint, diesen löschen 5. Schritt: Obiges Programm eingeben 6. Schritt: Mit <F5> Programm starten 7. Schritt: Programm testen, gegebenenfalls korrigieren 8. Schritt: Mit <Alt><F11> zurück zu Excel In Zukunft sollten alle Quelltexte in Textdateien abgespeichert werden (Pro-grammcode markieren, kopieren, in ein Textverarbeitungsprogramm einfügen und Dokument abspeichern). Hinweis: Dieses Programm kommt ohne selbstdefinierte Klassen aus. Da diese Art der Programmierung nicht das Ziel dieser Lernmaterialien ist, wird dieser Weg nicht weiter beschritten. Allerdings ist es wichtig, dass die Eingabe und das Testen dieses Programms auch wirklich funktionieren und nachvollziehbar sind. Andernfalls werden die weiteren Übungen kaum zum Erfolg führen. 11 Und jetzt die Klasse: Die Klasse besitzt drei Attribute und zwei Methoden. Damit lässt sich in der Realität selbstverständlich kein Fahrzeug hinreichend modellieren – es geht jetzt zunächst darum, die Klasse und ein dazu passendes Testprogramm in VBA zu implementieren. Auf Folgendes ist zu achten: Klassen werden in eigenen Quellcodebereichen erfasst: Jede Klasse steht in einem eigenen Klassenmodul. Das Programm, welches auf die Klassen zugreift (das „Hauptprogramm“), steht in dem Quellcodebereich, der oben schon beschrieben wurde. Hier wird nun der ganze Vorgang nicht in der EXCEL-VBA-Programmierumgebung vorgeführt, sondern in WORD-VBA. Zunächst wird nicht erklärt, wie das Programm funktioniert, sondern es wird eingetippt und getestet. Die Erklärungen erfolgen danach. 1. Schritt: Von WORD in VBA mit <ALT><F11> Es ist nun sinnvoll, diesen Namen auf „Testprogramm“ (o. ä) umzubenennen. Dies erfolgt in diesem Feld (mit der Maus in das Feld gehen, alten Namen überschreiben). 12 2. Zunächst wird die Klasse erfasst: Hier den Menüpunkt „Klassenmodul“ anwählen … … und das neue Klassenmodul anlegen. 13 Doppelklick auf Klasse1… …und den Namen ändern! Änderung! 14 Die Klasse: 3. Das Testprogramm (auch: Standardmodul): 15 4. Programm starten: <F5> Es ist sinnvoll, das Word-Dokument abzuspeichern, der Quellcode wird „automatisch“ mit abgespeichert. Und es funktioniert (falls kein Tippfehler vorliegt): Andere Möglichkeit des Programmaufrufs: 16 5. Erklärung (Klasse): Option Explicit Das bedeutet, dass alle Variablen (Begriff wird später genauer erklärt) ausdrücklich „angemeldet werden müssen. Private Hersteller Das Attribut „Hersteller“ darf nur von „Verarbeitungsschritten“ der eigenen Klasse manipuliert werden (Kapselung). Das Gegenstück wäre „Public“, wenn die Attribute allerdings dann „von überall“ verändert werden können, ist das Einrichten einer Klasse eigentlich unsinnig. Hier fällt noch etwas auf: Ein Datentyp muss hier nicht unbedingt angegeben werden. VBA kennt einen „universellen Datentyp“ (wird später genauer erklärt). Hinweis: Später werden Attribute und Methoden der Klassen auch als „Privat“ oder „Public“ gekennzeichnet. Sub erfassen(her, ty, hub) Sub kennzeichnet eine Methode der Klasse, in den Klammern stehen Platzhalter (Variablen) für die Daten, die von außen (vom Testprogramm) dem Objekt übermittelt werden. Die Verarbeitungsschritte stehen zwischen Sub und End Sub. Hersteller = her Das Attribut „Hersteller“ erhält den Wert, der in Her von außen an das Attribut übermittelt wurde. Beachte: Links steht der Empfangs-Platzhalter, rechts der Sende-Platzhalter. 17 Function ErmittleTyp() “Function” ist eine besondere Methode: Sie kann einen Wert an das Testprogramm zurückliefern. Der Name der Funktion hat dann die Bedeutung eines Platzhalters. In den Klammern könnte auch noch ein Platzhalter stehen, der einen Wert an diese Methode liefert. Das ist hier aber nicht der Fall. (Das kommt später). Andere Programmiersprachen verlangen, dass der Funktion selbst auch ein Datentyp (Typ des Rückgabewerts) zugeordnet werden muss. . In VBA muss man das nicht machen, dies kann allerdings dann auch in speziellen Fällen zu Fehlern führen. An späterer Stelle werden in diesen Unterlagen den Funktionen auch Typen zugeordnet. ErmittleTyp = Typ Der im Objekt gespeicherte Wert für den Autotyp soll an das Testprogramm zurückgeliefert werden. Wie oben: Links steht der Empfangsplatzhalter (hier der Name der Funktion), rechts das Sendefeld (hier ein Attribut-Name). 6. Erklärung (Testprogramm): Bemerkung: Das Testprogramm setzt hier die Werte der Attribute. In der Praxis wäre die Quelle dieser Daten z. B. eine Datenbank. Ein Programm, welches die Daten zunächst setzt und dann unmittelbar danach wieder abfragt, ist aus der Sicht der Praxis „unsinnig“. Es wäre eher so, dass ein Programm für die Erfassung der Daten zuständig ist und ein anders für die Weiterverarbeitung. Das wird auch später so in diesen Unterlagen vorgeführt – jetzt geht es zunächst einmal nur darum, den „Mechanismus“ zu begreifen. Daher wurde auch die Bezeichnung „Testprogramm“ gewählt! 18 Ein weiteres Beispiel: Für den Autoteile-Zubehör-Shop ist eine ähnliche Klasse wie beim vorherigen Beispiel festzulegen. Die Verkaufspreisberechnung funktioniert folgendermaßen: Der VK-Preis (netto) ergibt sich aus dem Einkaufspreis multipliziert mit dem Kalkulationsfaktor (Prozentzahl). Erklärungen: Integer: Der Platzhalter „Artikelnummer“ (Variable) steht für eine Zahl ohne Nachkommastellen. Double: Der Platzhalter „EK_PREIS“ (Variable) steht für eine Zahl mit Nachkommastellen. Der Unterstreichungsstrich „_“ darf in einem Namen für eine Variable oder eine Methode benutzt werden Das Testprogramm soll die Methoden der Klasse testen. Die Klasse: Option Explicit Private Artikelnummer As Integer Private Bezeichnung As String Private EK_Preis As Double Private K_Faktor As Double Diese Typenangabe muss in VBA nicht erfolgen. Sub erfassen(EkP As Double) Artikelnummer = 1234 Bezeichnung = "Sitzschoner" K_Faktor = 50 EK_Preis = EkP End Sub Function Ausgeben_Bezeichnung() Ausgeben_Bezeichnung = Bezeichnung End Function Function Ermitteln_VK_Preis() As Double Ermitteln_VK_Preis = (EK_Preis * K_Faktor / 100) + EK_Preis End Function Hinweise: Gerechnet wird wie in der Mathematik, das Empfangsfeld steht immer links. Aus Gründen der Vereinfachung wurden bis auf den EK_Preis alle Daten in der Methode „erfassen“ direkt festgelegt. 19 Das Testprogramm: Sub Testprg() Dim Autoz As Kfz_Zubehoer Dim bez As String Dim EP As Double Dim VkP As Double Set Autoz = New Kfz_Zubehoer EP = InputBox("Bitte Einkaufspreis eingeben: ") Autoz.erfassen EP MsgBox (Autoz.Ausgeben_Bezeichnung) MsgBox (Autoz.Ermitteln_VK_Preis) Set Auto1 = Nothing End Sub Hier wurde lediglich der EK_Preis an das Objekt übermittelt. Das ist natürlich „willkürlich“ (s. die Bemerkungen zum ersten Testprogramm). Zugriffe auf Eigenschaften Die letzte Klassendefinition zeigt, dass es offensichtlich zwei „Sorten“ von Methoden gibt. Die eine „Sorte“ ist letztlich nur dafür da, den Objekteigenschaften Werte zuzuweisen oder diese Werte abzurufen: Sub erfassen(EkP As Double) ……………… Function Ausgeben_Bezeichnung() As Double ……………… Die zweite „Sorte“ führt kompliziertere Dinge durch, hier die Berechnung eines neuen Wertes aus zwei Eigenschaften/Attributen der Klasse: Function Ermitteln_VK_Preis()As Double Ermitteln_VK_Preis = (EK_Preis * K_Faktor / 100) + EK_Preis End Function Es erscheint sicher sinnvoll, diesen Unterschied in der Implementierung zu Ausdruck zu bringen. Dies erfolgt mit den Eigenschaftsprozeduren Property Let (Wert setzen) Property Get (Wert auslesen). Hierbei handelt es sich um eine Alternative zu den bisherigen Möglichkeiten, Attributwerte zu setzen oder zu lesen. Angesprochen ist also nur die erste „Sorte“ Methoden (s. o.), für „Function Ermitteln_VK_Preis()“ bleibt alles so, wie bisher. 20 Die neue Lösung: Hinweis: Wie gleich erkennbar ist, werden die Attribute auf eine andere Art wie bei den vorherigen Beispielen gesetzt bzw. gelesen. Zur Kennzeichnung der Attributnamen einer Klasse steht hier nun ein „m“ vor jedem Variablenamen (m: Member, Mitglied der Klasse). Option Explicit Private mBezeichnung As String Private mEK_Preis As Double Private mK_Faktor As Double Diese Prozedur schreibt den aus dem Testprogramm übergebenen Wert des Parameters in die links stehende Variable. Public Property Let Artikelbezeichnung(Bez As String) mBezeichnung = Bez End Property Public Property Let Einkaufspreis(EkP As Double) mEK_Preis = EkP End Property Diese Prozedur gibt den Wert des Attributs mBezeichnung unter dem Namen „ArtikelPublic Property Let K_Faktor(KF As Double) bezeichnung“ an das Testprogramm mK_Faktor = KF zurück End Property Public Property Get Artikelbezeichnung() As String Artikelbezeichnung = mBezeichnung Diese Prozedur (genauer: Funktion) End Property berechnet etwas und gibt das Ergebnis unter dem Funktionsnamen „Ermitteln_VK_Preis“ an das Testprogramm zurück Double zurück Function Ermitteln_VK_Preis() As Ermitteln_VK_Preis = (mEK_Preis * mK_Faktor / 100)+EK_Preis End Function Property bedeutet „Eigenschaft“. In der Klasse scheint sich kaum etwas geändert zu haben, aus Sub Erfassen(EKP as Double) wurde Public Property Let Einkaufspreis (EK As Double). (Vor Sub hätte auch „Public“ stehen können, steht nichts da, ist die Prozedur/ Funktion automatisch public!) 21 Das Testprogramm: Sub Testprg() Dim Autoz As Kfz_Zubehoer Dim Bez As String Dim EP As Double Dim VkP As Double Neu! Set Autoz = New Kfz_Zubehoer Autoz.Artikelbezeichnung = "Sitzschoner" Autoz.K_Faktor = 50 EP = InputBox("Bitte Einkaufspreis eingeben: ") Autoz.Einkaufspreis = EP MsgBox (Autoz.Artikelbezeichnung) MsgBox (Autoz.Ermitteln_VK_Preis) Set Auto1 = Nothing End Sub Hier könnte man den Eindruck haben, dass ein direkter Zugriff auf das Attribut des Objektes möglich wäre. Das ist natürlich nicht der Fall! Das Geheimhaltungsprinzip gilt immer noch, die Attribute sind gekapselt. Der „echte“ Name des Attributs laute ja „mBezeichnung“ und nicht „Artikelbezeichnung“. Das Arbeiten mit Properties „vereinfacht“ das Setzen der Attribute aus der Sicht des Testprogramms. Genau wie bei „normalen“ Methoden können in Property-Prozeduren noch weitere Programmzeilen stehen (z. B. Plausibilitätsprüfungen hinsichtlich der übergebenen Werte). Nun kann auf folgenden Unterschied hingewiesen werden: Objekte besitzen zwei „Sorten“ von Attributen: Felder und Eigenschaften. Die intern vereinbarten Attribute (z. B. mBezeichnung) sind Objektfelder. Eigenschaften sind das, was die Objekte nach außen hin „preisgeben“ (z. B. Artikelbezeichnung). Für das Testprogramm sieht es nun so aus, als ob es direkt auf die Objektfelder zugreifen könnte: Autoz.K_Faktor = 50. In Wirklichkeit kapseln die Objekteigenschaften aber nur die Zugriffe auf Felder. Die Objekteigenschaft Artikelbezeichnung speichert selbst keinen Wert, sondern dient gleichsam nur der Übergabe eines Wertes. Objektfelder hingegen belegen „normale“ Speicherplätze. 22 3 Module, Klassenmodule und UserForms Vor dem eigentlichen Einstieg in die Programmierung sind noch einige Aspekte der Programmierumgebung zu klären. Wie bereits oben gezeigt, bietet das Menü „Einfügen“ mehrere Möglichkeiten an. Die für uns wichtigen Bereiche! 1. Ab sofort werden Testprogramme und Programmmodule, die nicht direkt objektorientiert vorliegen (also keine Klassen oder komplexere Dialogboxen beinhalten), im Bereich Module erfasst. Diese Art der Programmierung hat in diesen Unterlagen nur eine untergeordnete Bedeutung (z. B. Erstellung von Testprogrammen). Unter ThisDocument (s. oben) gehören nur noch „Subs“, die einen direkten Bezug zum WordDokument (oder bei EXCEL entsprechend „Diese Arbeitsmappe“) haben. Beispiel: Anlegen eines neuen Moduls und Namen ändern! 23 2. Klassen werden (wie bereits beschrieben) als Klassenmodule erfasst (also nicht Neues!). 3. Das Arbeiten mit MsgBox und InputBox ist nur in Ausnahmefällen sinnvoll. „Normalerweise“ wird mit „echten“ Windows-Masken gearbeitet, welche in VBA als UserForm(s) vorliegen. Bei UserForms handelt es sich um Container-Objekte, welche andere Objekte (z. B. TextBoxes oder Labels) enthalten. Das Erstellen solcher Masken ist in modernen objektorientierten Umgebungen äußerst einfach, da die internen Verarbeitungsschritte gleichsam gekapselt sind. Wie auch in der Programmiersprache Delphi (o. a.), wird die Arbeit im Wesentlichen von einer „Toolbox“ erledigt, Entwickler müssen lediglich einige Mausklicks beherrschen. Dialogboxen bieten unzählige Möglichkeiten. Für den Anfang reichen folgende Funktionalitäten: Bildschirmmaske (User Form): Hier wurden zwei Eingabefelder und ein Ausgabefeld (Ergebnis der Verarbeitung) festgelegt. Zwei unterschiedliche Ereignisse können ausgelöst werden: Klick auf Button „Aktion 1“ und/oder auf Button „Aktion 2“. Die Erstellung dieser User Form wird nun vorgestellt. Damit aber auch ein Programm „dahintersteht“, welches „etwas macht“, wird Folgendes vereinbart: In die Eingabefelder 1 und 2 können kleine Texte (z. B. Vor- und Zuname) eingegeben werden. Ein Klick auf „Aktion 1“ löst eine Ereignisprozedur aus, welche diese beiden Texte aneinanderfügt und das Ergebnis im Ausgabefeld anzeigt. Ein Klick auf Aktion 2 bewirkt, dass alle drei Felder wieder gelöscht werden. Beendet wird das Programm, wie alle Windows-Programme beendet werden können: Klick auf X. 24 User Form anlegen Nach dem Klick auf <Einfügen><UserForm> erscheint eine „Werkzeugsammlung und eine leere Maske: Klick auf das Zeichen A: Labelfeld (Überschrift oder Führungstext) auf der Maske erzeugen Ergebnis: Caption ändern Schriftgröße, -art usw. ändern 25 Die Eigenschaften wurden geändert, auch das ist oo Programmierung! Nächster Schritt: Edit-Feld (Textfeld) hinzufügen Ein Eingabefeld ist nun auf der Maske platziert: 26 Die Vorgänge mehrmals wiederholen und die Objekte auf der Forms richtig platzieren: Doppelklick auf den Button, dem Code zu hinterlegen ist Nun schaltet das System in den Quellcode-Editor um: Automatisch wird nun der Rahmen für die Ereignisprozedur erstellt! Quellcode: Neu eingefügter Quellcode: Zwei „Strings“ zusammenfügen (geht auch mit „+“) 27 Programmtest (F5): Objektorientierung bis auf die „unterste Ebene“: Für die User Form und alle ihre Objekte (Buttons, Label usw. existieren Eigenschaftstabellen! 28 Und zum Schluss: Eingabe von Zahlen, mit denen auch gerechnet wird: Private Sub CommandButton1_Click() Dim i As Double Dim k As Double i = TextBox1 k = TextBox1 + 1.89 TextBox2 = k End Sub Dieses Testprogramm zeigt, dass das Objekt TextBoxX auch in der Lage ist, Zahlen entgegenzunehmen und mit ihnen zu rechnen, wenn die entsprechende Variable als „Zahlentyp“ deklariert wurde. Das, was in TextBox1 eingegeben wurde, muss dann zunächst dieser Variablen zugeordnet werden. Allerdings erkennt diese Art der Zahleneingabe keine fehlerhaften Eingaben, auch die Ausgabe ist nicht immer optimal. Hinweis: Bisher wurden einige Grundlagen der VBA-Programmierung mit Objekten vorgestellt, viele wichtige Aspekte fehlen (noch). Allerdings sollte es nun möglich sein, prinzipielle Programmstrukturen mit VBA zu erstellen und zu testen. 29 4 Die logischen Grundstrukturen 4.1 Algorithmus und Struktogramm Bisher stand die Überlegung im Mittelpunkt, wie Objekte der realen Welt modelliert werden können, damit die hieraus gewonnene Modellwelt hinsichtlich der Informationsverarbeitung im Computer auch in diesem abgebildet werden kann. Die Modellierung von Klassen und die Erzeugung von Objekten sind wichtige Ergebnisse. Mit Methoden erfolgt die Verarbeitung der Daten. Die bisher vorgeführten Verarbeitungsschritte waren letztlich trivial und selbsterklärend. Was aber, wenn komplexere Schritte erforderlich werden? Dies ist die Thematik der nächsten Kapitel. Zur Veranschaulichung der Verarbeitungsfolgen in einem Programm existieren verschiedene, meist grafisch orientierte Darstellungsmittel, von denen das sogenannte Struktogramm eine weite Verbreitung hat und in einer DIN-Vorschrift als Norm vorliegt. Das Struktogramm zeigt die notwendigen Verarbeitungsschritte in der richtigen Reihenfolge, die erforderlich sind, um z.B. Eingabedaten in Ausgabedaten zu überführen, also das, was die Aufgabe vieler Methoden von Klassen darstellt. Hinweis: Auch UML bietet in diesem Bereich Möglichkeiten an, allerdings sind Struktogramme weiterhin relevante und einfach zu handhabende Darstellungsmöglichkeiten der Ablauflogik. Es muss aber auch festgehalten werden, dass Struktogramme z. B. im Bereich der Ereignissteuerung versagen. Die Gesamtheit der Verarbeitungsschritte wird auch als Programmlogik oder Ablauflogik bezeichnet. Diese Verarbeitungsschritte sind Arbeitsvorschriften (in Form einer Anweisungsliste) an die verarbeitende Instanz. Diese muss nicht unbedingt ein Computer sein; wenn z.B. eine Rechnung von Hand geschrieben wird, wäre ein Mensch derjenige, der die Anweisungen ausführt. Ein sogenannter Algorithmus ist eine Anweisungsliste, die folgende Kriterien erfüllt: Die Anweisungen sind eindeutig und ausführbar, ihre Anzahl endlich und ihre Befolgung liefert nach endlich vielen Schritten die Lösung eines Problems. Eindeutigkeit: der nachfolgende Schritt wird nicht zufällig ausgewählt, sondern liegt (z. B. aufgrund der aktuell vorhandenen Daten) eindeutig fest, der Algorithmus ist deterministisch. Anders gesagt: Die Reihenfolge der Abarbeitung ist nicht willkürlich, und gleiche Eingabewerte führen bei wiederholter Abarbeitung eines Algorithmus zu den gleichen Ausgabewerten. Ausführbarkeit: die einzelne Anweisung muss für den Ausführenden des Algorithmus (den „Prozessor“) verständlich und ausführbar sein (die „Befehle“ sind dem Prozessor bekannt). Ein ("funktionierendes") Computerprogramm ist demnach ein in einer Computersprache formulierter Algorithmus. Der Algorithmus: gibt an, wie Eingabegrößen schrittweise in Ausgabegrößen umgewandelt werden. 30 Beispiel für ein Struktogramm: Aufgabe: Im Umfeld einer Fakturierung existiert eine Methode zur Berechnung des Bruttopreises. Prozedur: Brutto_berechnen Berechne MWST_Betrag aus dem MWSTProzentsatz und dem Nettobetrag Bruttobetrag = Nettobetrag + MWST_Betrag) (Beachte die unterschiedliche Formulierung der beiden Verarbeitungsschritte! Wie diese Methode mit Daten versorgt wird bzw.wie die Daten weitergeleitet werden, ist im Moment unwichtig.) Ein Struktogramm besitzt einen Namen („Rechnungsfuß“) Anfang und Ende sind durch das Rechteck festgelegt, verbale Bezeichnungen wie „Anfang“ bzw. „Ende“ gibt es laut DIN nicht. Hinsichtlich der Formulierungen in den einzelnen Verarbeitungsschritten gibt es keinen Einschränkungen, sie müssen natürlich verständlich sein. In Struktogramm steht jeder Verarbeitungsschritt in einem Rechteck und ist so formuliert, dass die Ablauflogik auch einem Personenkreis, der keine spezielle Programmiersprache beherrscht, verständlich ist. U. U können auch mehrere Schritte zu einem zusammengefasst werden. Die Überführung der Programmlogik in eine Computersprache (z.B. in VBA) wird als Codierung bezeichnet: MWST_Betrag = (Netto * MWST_Proz) / 100 Bruttobetrag = MWST_Betrag + Netto Beachte: Viele Wege führen zum Ziel, das „Problem“ könnte auch mit einer einzigen Formel berechnet werden! Modellierung des Systems 1. Grundsätzlich: Es erfolgt eine Trennung von GUI (Benutzeroberfläche, und Fachkonzept (Berechnung), das (Fachkonzept-) Programm ist als Klasse implementiert und kann mehrfach verwendet werden. 2. Der Mehrwertsteuersatz wird in der Klasse clsBrutto als Konstante (19%) implementiert. (Dies ist eine Entscheidung, die unterschiedlich bewertet werden kann!) 3. Die Klasse liefert sowohl der Brutto-Betrag als auch den Mwst-Betrag zurück. 4. Auf Plausibilitätsprüfungen wird vorläufig verzichtet. 5. Die GUI hat zwei Schaltflächen: „Berechnen“ und „Felder leeren“. 6. Sie besitzt ein Eingabefeld und zwei Ausgabefelder (s. Punkt 3). 31 Klasse Brutto-Betrag und Mwst-Betrag treten hier nicht als Attribute auf. Es handelt sich um Funktionsrückgabewerte; dies wird später berücksichtigt (vgl. die Modellierung der Klasse clsBrutto einige Seiten weiter). GUI Struktogramm für die Berechnung: s. oben Klassenmodul clsBrutto Option Explicit Private mNetto_Preis As Double Public Property Let Nettopreis(NPr As Double) mNetto_Preis = NPr Hinweis: Dies wird später End Property noch „eleganter“ gelöst! Public Function Ermitteln_Brutto()As Double Dim Mwst_Betrag Mwst_Betrag = (mNetto_Preis * 19 / 100) Ermitteln_Brutto = mNetto_Preis + Mwst_Betrag End Function Public Function Ermitteln_Mwst()As Double Ermitteln_Mwst = (mNetto_Preis * 19 / 100) End Function 32 Quellcode User Form Option Explicit Dim oBrutto As clsBrutto Dim net As Double Private Sub CommandButton1_Click() Set oBrutto = New clsBrutto net = TextBox1 oBrutto.Nettopreis = net TextBox2 = oBrutto.Ermitteln_Brutto TextBox3 = oBrutto.Ermitteln_Mwst Set oBrutto = Nothing End Sub Private Sub CommandButton2_Click() TextBox1.text = " " TextBox2.text = " " TextBox3.text = " " End Sub Programmtest: Allerdings sollte hier klar sein, dass noch kein gesamtes Modell für diese Problemlösung vorliegt. Schwerpunkt der folgenden Betrachtung bleiben die logischen Grundstrukturen, vier Aspekte hinsichtlich der Modellierung fehlen noch: Modellierung der Ereignisbehandlung Modellierung der GUI Beziehungen zwischen den Klassen (GUI und Fachkonzept) Genaueres zur Datenmodellierung (Datentypen usw.) 33 4.2 Exkurs I: Botschaften und Ereignisse „Botschaften senden“ ist eine zentrale Sichtweise der objektorientierten Programmierung. Es handelt sich dabei um eine Aufforderung eines „Senders“ (der ein Objekt sein kann) an ein Objekt, eine seiner (public-) Methoden auszuführen. Beispiel: Benutzeraktion: Klick auf Button „Berechnen“ Windows (das OS) wertet dieses Ereignis aus und sendet eine Botschaft (z.B. CommandButton2 gedrückt, siehe UserForm) an das Objekt, über dem sich der Mauszeiger befindet. Diese Botschaft löst eine Ereignisbehandlungsroutine aus, welche von Anwendungsentwicklern erstellt wurde: Private Sub CommandButton2_Click() TextBox1.text = " " …………. End Sub Die einzelnen Objekte (Buttons, Felder usw.) gehören jeweils zu einer UserForm (Dialogfenster) – Windows sendet letztlich die Botschaft an diese. Das Dialogfenster „verarbeitet“ die Botschaft entsprechend dem Objekt, das betroffen ist. Der Button „liegt“ auf dem Fenster, die Ereignisbehandlung erfolgt in der speziellen UserForm-Klasse. Während der Ablauf in einer Methode (wie oben, z. B. MWST berechnen) nach einem festgelegten Plan (Struktogramm) abläuft, ist dies für die gesamte Programmsteuerung nicht so. Das Laufzeitsystem reagiert bei einem ereignisgesteuerten Programm permanent auf Benutzereingaben – ein Struktogramm kann dies nicht visualisieren. UML bietet hierzu professionelle Möglichkeiten an, die allerdings an dieser Stelle etwas zu komplex wären. Eine einfache Möglichkeit, welche die Modellierung kleinerer Problemstellungen gestattet, ist die Ereignistabelle: 34 4.3 Exkurs II: Modellierung der Benutzeroberfläche UserForm1 Label4 Label1 TextBox1 Label2 TextBox2 Label3 TextBox3 CommandButton1 CommandButton2 Sinnvoll ist es, die Bezeichner „UserForm1“, „Label1“ usw. umzubenennen: UserForm1: Maske_MWST, Label1: N_Label usw. Dies soll bei den folgenden Problemlösungen berücksichtigt werden. 35 4.4 Exkurs III: Beziehungen zwischen den Klassen Wie ist nun der Zusammenhang von GUI und Fachkonzept zu modellieren? Die UserForm ist zwar für die Ereignisbehandlung zuständig (s. Ereignistabelle), die eigentliche „fachliche“ Arbeit erledigt aber das Fachkonzept. Wie der Quellcode zeigt, erzeugt die GUI in unserem Beispiel das Objekt des Fachkonzeptes: Set oBrutto = New clsBrutto Nun kann dieses Objekt benutzt werden, d. h. die Methoden, die es (öffentliche) zur Verfügung stellt, können aufgerufen werden. Vereinfacht ausgedrückt: Das Fensterobjekt ist mit seinem Fachkonzept verbunden: Zwischen dem Dialogfenster und dem Fachkonzeptobjekt besteht eine sogenannte Assoziation. Das Fensterobjekt kann Daten an das Fachkonzept übergeben: oBrutto.Nettopreis = net und von diesem auch Daten empfangen: TextBox2 = oBrutto.Ermitteln_Brutto Modellierung der Assoziation: oBrutto:clsBrutto UserForm1:UserForm oBrutto: net : brut : mwst : clsBrutto Double Double Double Labels, Felder, Buttons: Object mNetto : Double benutzt Click_Berechnen_ und_anzeigen() Click_Felder_loe() Netto_setzen(NPr: double) Brutto_ermitteln(): double Mwst_Betrag_erm(): double Durch Brutto_ermitteln(): double wird zum Ausdruck gebracht, dass ein Wert vom Typ Double zurückgegeben wird. Damit ist klar, dass es sich bei dieser Methode um eine Funktion handelt. Die UserForm1 kennt die Fachklasse, der Benutzer steuert die Fachklasse über die GUI. Er gibt einen Nettopreis ein und klickt auf den Button „Berechnen“: Senden einer Botschaft an die Fachklasse, welche den „Auftrag“ ausführt und Daten zurückliefert. In der Ereignistabelle (letzte Spalte) ist erkennbar, dass die Methoden eines Objektes aufgerufen werden und nicht lediglich Prozeduren der UserForm1. Die Klassen werden hier ohne TextBox-Komponenten modelliert (dies erfolgte bereits in der Modellierung der Benutzeroberfläche). Die Attribute brut und mwst entsprechen in der Userform den TextBoxKomponenten 2 und 3. Man könnte auch lokale Hilfsvariablen (net und brut) in der Userform expliziet definieren (so wie es oben bei UserForm1 den Anschein hat) und diese den TextBox-Komponenten zuweisen. Dieses Klassenmodell auf dieser Seite entspricht also nicht 100% dem zuvor dargestelltem Quellcode. 36 4.5 Exkurs IV: Genaueres zu Variablen, Konstanten und Datentypen Das Programm "Bruttobetrag berechnen" kann zu jedem beliebigen Nettopreis den Bruttopreis berechnen: der Nettopreis ist "variabel". In der Mathematik werden beim Formelrechnen Platzhalter (= Variablen) verwendet: z. b.: Z = K * P / 100 Bei einer konkreten Berechnung werden dann für die Platzhalter Zahlen eingesetzt. Computer arbeiten ähnlich. Damit dies möglich ist, wird der Wert unmittelbar nach seiner Eingabe zunächst im Speicher abgelegt. Für die sich daran anschließende Berechnung werden die Werte dann aus diesem abgerufen, die Berechnung ausgeführt und das Ergebnis wieder gespeichert, bevor es dann ausgegeben wird. Der Computer hat intern seine Speicherzellen durchnummeriert. In der Programmierung ist es aber sinnvoller, nicht mit diesen "Hausnummern" zu arbeiten (was durchaus auch möglich ist!), sondern mit sogenannten sprechenden Namen als Platzhalter/Variablen (z. B. "brut" für Bruttobetrag). Bei der Programmausführung werden dann diese Platzhalter durch die "echten" Speicheradressen ersetzt. Variablen haben also immer einen Variablennamen und einen Inhalt (Wert). In der Zeile Dim net As Double wird die Variable mit dem Namen "net" vereinbart. Der Zusatz "As Double" sagt etwas über den Variablentyp aus; dies wird später erklärt. Das Wort "Dim" bedeutet in etwa: Achtung, jetzt erfolgt eine Variablendeklaration (Variablenvereinbarung). Eine Programmmodifikation: Option Explicit Private mNetto_Preis As Double Private Const mp = 19 …………………… Function Ermitteln_Brutto() As Double Dim Mwst_Betrag Mwst_Betrag = (mNetto_Preis * mp / 100) …………………… Der Prozentwert für die Mehrwertsteuer (mp) wurde hier nicht als Variable, sondern als sogenannte Konstante (Const) vereinbart. Konstanten können während der Programmausführung ihren Wert nicht ändern. Sollte sich der Mehrwertsteuersatz mal wieder ändern, müsste das Programm an dieser Stelle geändert werden. 37 Zu der Zeile Mwst_Betrag = (mNetto_Preis * mp / 100) ist noch folgendes zu sagen: Hier werden eigentlich zwei Anweisungen ausgeführt. Zunächst wird eine Berechnung durchgeführt (das was rechts vom Gleichheitszeichen steht, dann erfolgt eine sogenannte Wertezuweisung, d. h. das Ergebnis wird in den Speicherbereich mit dem Namen Mwst_Betrag geschrieben. Das Gleichheitszeichen ist hier nicht im mathematischen Sinne zu verstehen. So sind auch folgende Ausdrücke in der Programmierung sinnvoll: X = X + 1. Im Sinne einer mathematischen Gleichung wäre diese Formulierung unsinnig. Eine Variable kann unterschiedliche "Sorten" von Daten aufnehmen, wie. ganze Zahlen ohne Dezimalstelle (z. B. 23), Dezimalzahlen mit unterschiedlicher Genauigkeit (z. B. 34.765), einzelne Buchstaben (z. B. "a") oder Texte wie ganze Sätze "Hallo, wie geht es Dir?". In der Datenverarbeitung spricht man vom Datentyp der Variablen. Der Datentyp einer Variablen ist die dritte wichtige Eigenschaft neben dem Variablennamen und dem Variableninhalt, durch die eine Variable gekennzeichnet ist. Prinzipiell wird durch den Datentyp schon geklärt, was als Variableninhalt in Frage kommt. Oft ist dem Inhalt aber nicht ohne weiteres der Typ anzusehen. So können z. B. Variablen von dem Typ "Dezimalzahl" auch Zahlen ohne Dezimalstelle aufnehmen. Werden Variablen nicht deklariert, können sogar Text ohne feste Länge unter diesem Variablennamen abgespeichert werden. (Typ: Variant, von dieser Möglichkeit sollte man aber nur in Ausnahmefällen Gebrauch machen, die Programme werden u. U. langsamer, die Codierung schwerer nachvollziehbar.). Wird der Rückgabetyp einer Funktion nicht angegeben, wird ebenfalls automatisch der Typ Variant gesetzt. Bei der Variablendeklaration wird der Variablentyp entweder durch die Typenbezeichnung (... As Double) oder mit dem sogenannten Typenkennzeichen (z. B.: Dim rechbetrag#) festgelegt. Die folgende Tabelle gibt eine Zusammenfassung der verschiedenen Datentypen: Variablentyp Boolean Integer (Ganzzahl) Long (Ganzzahl) Single (Dez.-Zahl) Typenkennzeichen % & ! Double (Dez.-Zahl) # Currency (DezZahl, Währung) Date (Datum) String (Text) Variant @ $ Bereich 0 (False) und -1 (True) -32768 bis +32767 -2147483648 bis +2147483647 -3,402823*10 hoch -38 bis +3,402823*10 hoch 38 -1,797693*10 hoch -324 bis +1,797693*10 hoch 324 -9,22*10 hoch 14 +9,22*10 hoch 14 1.1.1000 bis 31.12.9999 ca. 2 Milliarden siehe oben 38 Speicherplatz in Bytes 2 2 4 4 8 8 8 10 + Textlänge 22 + Textlänge Hinweis: Bei den sogenannten. Literalen handelt es sich ebenfalls um konstante Werte eines bestimmten Typs, die im Quelltext explizit (ohne Namen) angegeben werden, z. B.: c = 19 * p 19 ist dann ein Literal. Ein weiteres Beispiel (hier: Erfassen als Standardmodul, nicht Klassenmodul oder UserForm): Sub test_var() a = 29 test = 2 MsgBox (test) test = 5.6 MsgBox (test) test = "Hallo, wie geht es Dir?" MsgBox (test) End Sub Beachten Sie bitte: Bei diesem Testprogramm wird absichtlich ohne Variablendeklaration gearbeitet, da hier ein spezieller Sachverhalt vorgeführt werden soll. Aufgabe 2: Testen Sie bitte dieses Programm (Standardmodul). Der Inhalt der Variablen mit dem Namen test hat hier drei verschiedene Inhalte. Wodurch unterscheiden sich diese (Länge, Wertebereich usw.)? Arbeitshinweis: Erstellen Sie eine kleine Skizze, die den Hauptspeicher (stark vereinfacht) darstellt und benennen sie einen Speicherbereich mit dem Namen test! Aufgabe 2a (Erweiterung von Aufgabe 2: Entwerfen Sie bitte ein kleines Testprogramm, welches die möglichen Zahlenformate veranschaulicht. Das Programm soll alle Variablen deklarieren. Danach verlangt es für jede Zahl eine Eingabe und gibt anschließend diese Zahl wieder aus. Was passiert bei der Eingabe von falschen Zeichen? Testen Sie auch Beispiele aus dem Unterricht zum kaufmännischen Rechnen! 39 Lineare Algorithmen Algorithmen, bei denen alle Anweisungen ohne Ausnahme und genau einmal durchlaufen werden, heißen lineare Algorithmen oder Reihung oder Sequenz. Bisher haben wir lediglich diese einfache Form von Programmen kennen gelernt. Die folgenden Aufgabenstellungen fassen das bisher Gelernte zusammen: Aufgabe 3: Ein Unternehmen gewährt 5% Rabatt. Nach der Eingabe des Warenwertes wird der Nettoverkaufspreis berechnet, der Mehrwertsteuerbetrag auf den Nettoverkaufspreis addiert und der Bruttopreis ausgegeben. - Modellieren Sie eine geeignete GUI und das Fachkonzept (UML) - Erstellen Sie ein Struktogramm! - Codieren Sie das Programm in VBA! Aufgabe 4: Eine Pizzeria bietet zusätzlich zu dem „normalen“ Pizza-Angebot für jede Pizzasorte eine Riesenpizza für sieben Personen an. Einzugeben ist der Preis für eine kleine Pizza der gewünschten Pizzasorte; ausgegeben wird der Preis der Riesenpizza. Dieser Preis berechnet sich aus dem Preis der kleinen Pizza multipliziert mit 7 minus einem Preisnachlass von 5,00 Euro. Erstellen Sie bitte das entsprechende Programm! Aufgabe 5: Erstellen Sie bitte ein Programm zur Zinsberechnung! Benutzen Sie folgende Formel: Zinsen = Kapital * Zinssatz * Tage / 100 * 360 Aufgabe 6: Ermitteln Sie mit Hilfe eines Programms den durchschnittlichen Benzinverbrauch eines Wagens! Aufgabe 7: Ein gemeinnütziger Verein führt ein Sommerfest durch. Die Besucher können ähnlich wie beim deutschen Lottosystem einen Lottoschein erwerben und auf diesem 10 Zahlen von 30 Zahlen ankreuzen. Ein Programm soll die Gewinnverteilung ermitteln: 1/3 der Gesamteinnahmen aus dem Lottoschein-Verkauf erhält der Verein. Vom Rest bekommt die erste Gewinnposition die Hälfte und was dann übrig bleibt, wird an die zweite und dritte Position zu gleichen Teilen verteilt. Die Gewinnposition richtet sich danach, wie viele richtige Zahlen angekreuzt wurden. Für den Fall, dass mehrere Personen gleich viele Zahlen richtig haben, ist ein Verfahren festgelegt, welches nicht Bestandteil dieser Aufgabe ist. In diesem Programm sollen lediglich die Beträge für die Gewinnpositionen ermittelt werden. 40 Verzweigte Algorithmen (Alternation, Auswahl) In den meisten Fällen muss ein Programm flexibel auf eingegebene Daten reagieren, d. h. je nach Eingabe sind unterschiedliche Verarbeitungsschritte abzuarbeiten. Das bedeutet, dass bei einem Programmlauf nicht alle Anweisungen durchlaufen werden, sondern nur die, die entsprechend der Eingabedaten durch eine Fallunterscheidung in Frage kommen. Ein Einführungsbeispiel möge den Fall verdeutlichen: Beispiel: Falls der Nettobetrag einer Rechnung 99,99,- überschreitet, sollen 3% Rabatt berücksichtigt werden. Hier zunächst eine vereinfachte Lösung mit „InputBox“ (lediglich ein Modul, kein Klassenmodul und keine UserForm): Option Explicit Sub rabatt_1() Dim net As Double Dim brut As Double Const rab = 3 Const mwst = 19 net = InputBox("Nettobetrag: ") If net > 99.99 Then net = net - (net * rab / 100) brut = ((net * mwst) / 100) + net MsgBox ("Rechnungsbetrag BRUTTO " & brut) End Sub (Hinweis: Auf die Ausgabe des Betrags für den Rabatt wurde hier aus Gründen der Vereinfachung verzichtet.) Die neue Anweisung für die Abfrage im Programm lautet: If ...Then.... Struktogramm: Programm rabatt Eingabe net net > 99.99? ja net = nett (net * rab / 100) nein ./. Bruttobetrag berechnen und ausgeben 41 In diesem Fall steht unter dem Nein-Zweig "./.". Dies bedeutet, dass dann, wenn der Netto-Betrag nicht größer als 99,99 ist, nichts gemacht wird. Nur im ja-Fall soll ein Rabatt berechnet werden. Der Fachbergriff für diese spezielle Situation lautet bedingte Anweisung (oder einseitige Auswahl). Die Abfrage "net > 99.99" ist eine Bedingung, die entweder wahr oder falsch sein kann. Aufgabe 8: Modellieren Sie nun eine geeignete GUI und das separate Fachkonzept (UML)! Entwickeln Sie dann die UserForm und das Klassenmodul! Codieren Sie das Programm in VBA! Mögliche Lösung (GUI und VBA): UserForm Option Explicit Dim oBrutto As clsRabatt Dim net As Double Private Sub CommandButton1_Click() Set oBrutto = New clsRabatt net = TextBox1 oBrutto.Nettopreis = net Brutto_aus.Caption = _ Brutto.Ermitteln_Brutto Set oBrutto = Nothing End Sub (Hinweis: das Ausgabefeld ist hier als Label festgelegt!) Fachkonzept (hier eine mögliche Lösung, Abfrage im Fachkonzept!): Option Explicit Private mNetto_Preis As Double Private Const mRab = 3 Public Property Let Nettopreis(NPr As Double) mNetto_Preis = NPr End Property Public Function Ermitteln_Brutto() As Double Dim Mwst_Betrag As Double If mNetto_Preis > 99.99 Then mNetto_Preis = _ mNetto_Preis - (mNetto_Preis * mRab / 100) Mwst_Betrag = (mNetto_Preis * 19 / 100) Ermitteln_Brutto = mNetto_Preis + Mwst_Betrag End Function 42 Trennzeichen, wenn eine Anweisung noch nicht zu Ende ist und in der nächsten Zeile weitergeht: Leerzeichen + „_“ Neue Objekte auf der GUI: Soll eine Verkaufspauschale von 5 Euro berücksichtigt werden, ist der entsprechende Optionsbutton anzuklicken. Die Zusätze der GUI werden mit diesen Steuerelementen (Objekten) der Werkzeugsammlung erstellt Aufgabe 9: Erstellen Sie bitte diese erweiterte GUI! VBA-Code: UserForm: Option Explicit Dim oBrutto As clsRabatt Dim netto As Double Dim brutto As Double Private Sub CommandButton1_Click() Set oBrutto = New clsRabatt netto = TextBox1 oBrutto.Nettopreis = netto brutto = oBrutto.Ermitteln_Brutto If OptionButton1.Value = True Then brutto = _ oBrutto.Ermittle_Br_Verpack_Pausch Brutto_aus.Caption = brutto Set oBrutto = Nothing End Sub 43 VBA-Code: Fachkonzept: Option Explicit Private mNetto_Preis As Double Private mBrutto_Preis As Double Private Const mRab = 3 Public Property Let Nettopreis(NPr As Double) mNetto_Preis = NPr End Property Public Function Ermitteln_Brutto() As Double Dim Mwst_Betrag As Double If mNetto_Preis > 99.99 Then mNetto_Preis = _ mNetto_Preis - (mNetto_Preis * mRab / 100) Mwst_Betrag = (mNetto_Preis * 19 / 100) mBrutto_Preis = mNetto_Preis + Mwst_Betrag Ermitteln_Brutto = mBrutto_Preis End Function Public Function Ermittle_Br_Verpack_Pausch() As Double Ermittle_Br_Verpack_Pausch = mBrutto_Preis + 5 End Function Aufgabe 10: Rekonstruieren Sie aus diesen Quellcodes die entsprechenden Klassen und erstellen Sie bitte die Logik der Methoden als Struktogramme. Beachten Sie bitte die Trennung zwischen GUI und Fachkonzept. Hinweis: Wie bei jeder Lösung gibt es auch hier Alternativen. Sie sollten sich für die Bearbeitung dieser Aufgabe genügend Zeit nehmen und mit der Lösung experimentieren, indem Sie Lösungsalternativen auch tatsächlich realisieren und testen. Für Ihre weiteren Fortschritte in der objektorientierten Programmierung ist es wichtig, dass Sie diese Problemlösung verstehen und durchschauen. 44 Alternative Anweisung (oder zweiseitige Auswahl): In vielen Fällen sind zwei Möglichkeiten zu berücksichtigen. Das Rabatt-Programm wird erweitert: Wenn der Netto-Preis über 99,99 € liegt, beträgt der Rabattsatz 5%, andernfalls sind 3 % zu berücksichtigen. Programm Rabatt_neu Eingabe netto netto > 99,99? ja rabatt = 5 nein rabatt = 3 weitere Berechnungen…. In VBA wird diese alternative Anweisung folgendermaßen codiert: If netto > 99.99 Then rabatt = 5 Else rabatt = 3 End If Hinweis: Das Struktogramm skizziert nur die Lösung und ist unvollständig. Hinweise zur Modellierung Es sollen alle bisher behandelten Möglichkeiten der Zugriffe auf Methoden und Attribute eines Objektes benutzt werden. Die Bruttoberechnung wird als Funktion (Methode der Klasse) modelliert, die aus einem Nettobetrag einen Bruttobetrag in Abhängigkeit eines ermittelten Rabatt-Satzes (3% oder 5%) und einer gesetzten (Let) Mehrwertsteuer) berechnet und auf der GUI ausgibt. Der Rabattsatz wird ausgelesen (Get) und auf der GUI ausgegeben. 45 Die Fachklasse: Option Explicit Private mNetto_Preis As Double Private mBrutto_Preis As Double Private mRabatt_st As Integer Private mwst As Integer Private Mwst_Betrag As Double Public Property Let mwst_init(m As Integer) mwst = m End Property Public Property Get Rab_aus() As Integer Rab_aus = mRabatt_st End Property Public Function Ermitteln_Brutto(n As Double) As Double mNetto_Preis = n If mNetto_Preis > 99.99 Then mRabatt_st = 5 Else mRabatt_st = 3 End If mNetto_Preis = mNetto_Preis - (mNetto_Preis * mRabatt_st / 100) Mwst_Betrag = (mNetto_Preis * 19 / 100) mBrutto_Preis = mNetto_Preis + Mwst_Betrag Ermitteln_Brutto = mBrutto_Preis End Function Die GUI Option Explicit Dim oBrutto As clsRabatt Dim netto As Double Dim brutto As Double Dim mwst As Integer Private Sub CommandButton1_Click() Set oBrutto = New clsRabatt mwst = 19 oBrutto.mwst_init = mwst netto = TextBox1 brutto = oBrutto.Ermitteln_Brutto(netto) Brutto_aus.Caption = brutto Label4 = oBrutto.Rab_aus Set oBrutto = Nothing End Sub Legen Sie die USER-Form an und testen Sie bitte das Programm. 46 Ein weiteres Beispiel: Eine Versicherung erstattet ihren Mitgliedern einen Teil des Jahres-beitrags zurück: bei mehr als 5-jähriger Mitgliedschaft 9%, andernfalls 4%. Programm rueckerstattung Eingabe beitrag_j, jahre jahre > 5? ja rueck = beitrag_j * 0,09 nein rueck = beitrag_j * 0,04 rueck ausgeben If jahre > 5 Then rueck = beitrag_j * 0.09 Else rueck = beitrag_j * 0.04 End If Beachten Sie bitte: Bei diesen komplexeren Formulierungen werden die Bedingungen und die Anweisungen jeweils in separate Zeilen geschrieben! Else ist der Zweig für die zweite Möglichkeit, mit End If wird die alternative Anweisung abgeschlossen, damit die sich daran anschließenden Programmzeilen nicht mehr an die If-Else-Konstruktion gebunden sind. Aufgabe 11: Entwickeln Sie bitte das komplette Programm zu diesem Struktogramm! (GUI und Fachkonzept getrennt!) 47 Unsere Aufgabe wird nun erweitert: die Versicherung erstattet ihren Mitgliedern einen Teil des Jahresbeitrags zurück, bei mehr als 10-jähriger Mitgliedschaft 14%, bei mehr als 5-jähriger Mitgliedschaft 9%, andernfalls 4% (Mehrfachauswahl). Programm rueckerstattung_neu Eingabe beitrag_j, jahre jahre > 10 ja rueck = beitrag_j * 0,14 nein jahre > 5 ja nein rueck = beitrag_j * 0,09 rueck = beitrag_j * 0,04 Ausgabe: rueck Codierung: ………… If jahre > 10 Then rueck = beitrag_j * 0.14 Else If jahre > 5 Then rueck = beitrag_j * 0.09 Else rueck = beitrag_j * 0.04 End If End If ………… Aufgabe 12: Auch für dieses Beispiel ist das komplette Programm zu entwickeln. (GUI und Fachkonzept getrennt!) 48 Aufgabe 13: Was passiert, wenn Sie die Abfragen jahre > 10 und jahre > 5 vertauschen? Formulieren Sie bitte eine genaue Begründung! Die Fallunterscheidung mit IF..ELSE.. IF..ELSE .. (auch mehrstufige Auswahl) ist eine Erweiterung der alternativen Anweisung. Für die Bedingung kommen nicht nur zwei Möglichkeiten (wahr/falsch) in Frage sondern mehr als zwei. Im Struktogramm kann die Fallunterscheidung als Schachtelung alternativer Anweisungen grafisch dargestellt werden. Eine andere Möglichkeit der grafischen Darstellung der Fallunterscheidung zeigt folgendes Struktogramm (Fallunterscheidung mit CASE, auch mehrseitige Auswahl): Programm rueckerstattung_neu_case Eingabe beitrag_j, jahre >10 rück = beitrag_j * 0,14 jahre? >5 rück = beitrag_j * 0,09 <= 5 rück = beitrag_j * 0,04 Ausgabe: rueck Für diese Struktur existiert in VBA eine spezielle Syntax: ………… Select Case jahre Case Is > 10 rueck = beitrag_j * 0.14 Case Is > 5 rueck = beitrag_j * 0.09 Case Else rueck = beitrag_j * 0.04 End Select ………… 49 Beachten Sie: Die If-Else-Struktur verschachtelt nach innen und wird bei steigender Anzahl der Möglichkeiten immer schwerer lesbarer, für die CaseStruktur gilt dies so nicht! Weiterhin: Der Case – Else – Fall wird i. d. R. etwas anders dargestellt, als im oben stehenden Struktogramm (bitte nachprüfen). Hinweis: Die Begriffe „Fallunterscheidung“, „mehrseitige/-stufige Auswahl“ usw. werden in Lehrbüchern teilweise nicht einheitlich benutzt. Aufgabe 14: Auch für dieses Beispiel ist das komplette Programm zu entwickeln. (GUI und Fachkonzept getrennt!) Testen Sie bitte folgende Programmänderung: Select Case jahre Case Is > 5 rueck = beitrag_j * 0.09 Case Is > 10 rueck = beitrag_j * 0.14 Case Else rueck = beitrag_j * 0.04 End Select Aufgabe 15: Beschreiben Sie die fehlerhafte Arbeitsweise des Programms! Worin unterscheidet sich dieses Programm von dem auf der vorherigen Seite? Versuchen Sie näher zu erklären, wie die Case-Struktur abgearbeitet wird! Aufgabe 16: Ein Weingut liefert an seine Kunden Wein frei Haus. Eine bestimmte Sorte kostet in einem Sonderangebot 4,00 Euro. Wenn ein Auftrag unter 100 Euro liegt, werden noch 8 Euro für die Verpackung verlangt. Ein Programm soll für eine einzugebende Anzahl Flaschen (Sonderangebot) den Nettopreis berechnen. Aufgabe 17: Ein Programm soll die Lösungen einer quadratischen Gleichung berechnen bzw. angeben, ob und wie viele Lösungen existieren. Einzugeben sind die Koeffizienten. Aufgabe 18: Ein Programm berechnet das zu zahlende Porto für Briefe (s. Gebührenverordnung). (Hinweis: Einsatz von Optionsbuttons) 50 Schleifen im Programm: Iteration (Wiederholung) Die Organisationsleitung einer Messe „Informationstechnologie für das Büro“ möchte wissen, wie viele Personen diese Messe pro Tag durchschnittlich besuchten. Nach der Eingabe der Messedauer (Tage) werden die absoluten Werte (Anzahl der Besucher) pro Tag eingegeben, der Durchschnitt berechnet und das Ergebnis ausgegeben. Programm: Messebesucher_Durchschnitt Eingabe tage z = 1, summe = 0 solange z <= tage Eingabe anzahl summe = summe + anzahl z=z+1 schnitt = summe / tage Ausgabe schnitt Codierung (hier wieder nur als Modul): Option Explicit Sub durchschnitt_1() Dim tage As Integer Dim anzahl As Double Dim summe As Double Dim schnitt Dim z As Integer tage = InputBox("Anzahl Tage: ") z = 1 summe = 0 Do While z <= tage anzahl = InputBox("Anzahl Besucher: ", anzahl) summe = anzahl + summe z = z + 1 Loop schnitt = summe / tage MsgBox ("Durchschnitt: " & schnitt) End Sub 51 Eine Wiederholungsstruktur ist durch folgende Eigenschaften gekennzeichnet: - Es existiert eine Abbruchbedingung: Wann ist das, was wiederholt werden soll, beendet? - Die zu wiederholenden Anweisungen (= Schleifenkörper, Anweisungsblock der Schleife) sind in irgendeiner Weise als zusammengehörend gekennzeichnet, z. B. durch Klammern (bei C++), begin … end (bei Delphi) oder do … Loop (bei VB/VBA). Im Struktogramm ist dies folgendermaßen realisiert: Bedingung Anweisung 1 Anweisung 2 Schleifenkörper, Block Anweisung 3, 4 ,5 usw. Die allgemeine Darstellung dieses Schleifentyps in VBA lautet: Do While Bedingung Anweisung 1 Anweisung 2 Anweisung 3, 4, 5 usw. Loop Bei diesem Schleifentyp, der Do-While-Schleife, wird zuerst abgefragt, ob der logische Ausdruck in Bedingung wahr oder falsch ist, erst dann erfolgt die Abarbeitung des Schleifenkörpers. Die Schleife wird also u. U. nicht ausgeführt, wenn die Anfangsbedingung nicht zutrifft („Überspringen“ der Schleife). Beim Erreichen des Schlüsselwortes Loop kehrt das Programm wieder an die Überprüfung der Bedingung zurück und führt den Schleifenkörper gegebenenfalls nochmals aus. Aufgabe 19: Überführen Sie das Programm „Messebesucher“ in die objektorientierte Form (Trennung GUI – Fachkonzept). Erstellen Sie bitte zunächst die Klassendiagramme. 52 Eine Programmänderung: Do Until z > tage anzahl = InputBox("Anzahl Besucher: ", anzahl) summe = anzahl + summe z = z + 1 Loop Aufgabe 20: Überprüfen Sie, ob das Programm mit dieser Änderung noch korrekt arbeitet. Beschreiben Sie die Änderung! Wie sieht das Struktogramm zu dieser Änderung aus? Ein anderer Schleifentyp: Bisher erfolgte die Schleifen-Ende-Abfrage immer vor der Ausführung des Anweisungsblockes. Sie kann aber auch erst nach der Ausführung des Schleifenkörpers erfolgen. das Struktogramm hat dann diese Form: Programm: Messebesucher_Durchschnitt_neu Eingabe tage z = 1, summe = 0 Eingabe anzahl summe = summe + anzahl z=z+1 solange z <= tage schnitt = summe / tage Ausgabe schnitt 53 Codierung: Option Explicit Sub durchschnitt_1() Dim tage As Integer Dim anzahl As Double Dim summe As Double Dim schnitt As Double Dim z As Integer tage = InputBox("Anzahl Tage: ") z = 1 summe = 0 Do anzahl = InputBox("Anzahl Besucher: ", anzahl) summe = anzahl + summe z = z + 1 Loop While z <= tage schnitt = summe / tage MsgBox ("Durchschnitt: " & schnitt) End Sub Aufgabe 21: Testen Sie das Programm und erklären Sie die Funktionsweise dieses Schleifentyps! Wo sehen Sie Probleme, wann könnte das Programm etwas „machen“, was nicht beabsichtigt ist? Aufgabe 22: Überführen Sie auch dieses Programm in die objektorientierte Form (Trennung GUI – Fachkonzept). Erstellen Sie bitte zunächst die Klassendiagramme. 54 Unterscheiden Sie bitte: Bedingung Anweisung 1 Anweisung 2 Anweisung 3, 4 ,5 usw. Schleifen von diesem Typ werden auch als „abweisende Schleife“ oder „kopfgesteuerte Schleifen“ bezeichnet. Anweisung 1 Anweisung 1 Anweisung 3, 4 ,5 usw. Bedingung Diese Schleifen heißen auch „nicht abweisende Schleife“ oder „fußgesteuerte Schleife“. Aufgabe 23: Je nach Schleifentyp kann vermieden werden, dass die Schleife überhaupt abgearbeitet wird: Eingabe Tage: 0. Trotzdem wird auch bei der vorliegenden Lösung dann unsinnigerweise ein Durchschnitt berechnet, was dann zu einem Laufzeitfehler (Division durch 0) führt. Erweitern Sie das Programm so, dass dies abgefangen wird (auch Struktogrammerstellung)! 55 Vermutlich sind Sie zu einer ähnlichen Lösung wie diese gekommen: Option Explicit Sub durchschnitt_3() Dim tage As Integer Dim anzahl As Double Dim summe As Double Dim schnitt As Double Dim z As Integer tage = InputBox("Anzahl Tage: ") z = 1 summe = 0 Do While z <= tage anzahl = InputBox("Anzahl Besucher: ", anzahl) summe = anzahl + summe z = z + 1 Loop If tage > 0 Then schnitt = summe / tage MsgBox ("Durchschnitt: " & schnitt) End If End Sub Als vierte Möglichkeit der Schleifenprogrammierung wird nun die For-NextSchleife vorgeführt, die in ähnlicher Weise in praktisch in allen Programmiersprachen vorhanden ist: ...... tage = InputBox("Anzahl Tage: ") summe = 0 For z = 1 To tage anzahl = InputBox("Anzahl Besucher: ", anzahl) summe = anzahl + summe Next z schnitt = summe / tage MsgBox ("Durchschnitt: " & schnitt) ...... 56 Die Variable z wird als Schleifenzähler benutzt und bei diesem Schleifentyp automatisch hochgezählt. Für viele Aufgabenstellungen ist dies eine sehr elegante und einfache Lösung. Allerdings gibt es Fälle, wo dieser Schleifentyp nicht die bestmögliche Lösung darstellt, z. B. wenn die Anzahl der Schleifendurchläufe bei Beginn der Abarbeitung unbekannt ist. Eine mögliche Struktogrammdarstellung: Eingabe: tage summe = 0 AW = 1, EW = tage, LV = z Eingabe anzahl AW: Anfangswert EW: Endwert LV: Laufvariable Manche Autoren benutzen folgende Formulierung der Bedingung: „Für z = 1 bis …..“ („klingt“ sprachlich etwas merkwürdig, die AW-EW – Formulierung erscheint dem Autor dieser Unterlagen sinnvoller). Aufgabe 24: Es ist ein Programm zu erstellen, welchen den Tilgungsplan eines Kredits ausgibt. Nach der Eingabe der Kredithöhe, des Zinssatzes, der jährlichen Rückzahlung und der Laufzeit soll eine Tabelle mit folgenden Angaben ausgegeben werden: Jahr Zins (in Euro) Tilgung Restkredit Wird eine Laufzeit < 1 oder größer 20 eingegeben, wird standardmäßig eine Laufzeit von 20 Jahren angenommen. Ihre erste Lösung sollte zunächst lediglich als Modul getestet werden. Erstellen Sie hierzu ein Struktogramm. Erst dann erarbeiten Sie die objektorientierte Lösung (s. nächste Aufgabe). 57 Lösung: Codierung: Option Explicit Sub tilgung() Dim k As Double Dim p As Double Dim r As Double Dim j As Integer Dim z As Double Dim t As Double Dim i As Integer Dim aus As String aus = "Jahr Zins Tilgung" aus = aus & " Restkredit" & vbCrLf k = InputBox("Kredit: ") p = InputBox("Zinssatz: ") r = InputBox("Jährl. Rückzahlung: ") j = InputBox("Laufzeit :") If j < 1 Or j > 20 Then j = 20 For i = 1 To j z = (k * p) / 100 t = r - z k = k - t aus = aus & Format(i, "00 ") & Format(z, "0000000.00 ") _ & Format(t, "0000000.00 ") & Format(k, "0000000.00") & vbCrLf Next i MsgBox (aus) End Sub Hinweise: Der String mit dem Variablenname "aus" beinhaltet die Ausgabezeilen und wird in der Verarbeitungsschleife zusammengesetzt. Das "&" verkettet die einzelnen Werte einer Zeile (die Berechnungen für ein Jahr); damit aber für jedes Jahr mit einer neuen Zeile begonnen wird, muss der Zeilenvorschub berücksichtigt werden (Code: vbCrLf). Die Formatangabe dient dazu, dass die sich entsprechenden Werte genau untereinander stehen (sauberer Tabellenaufbau); dass so allerdings führenden Nullen mit ausgegeben werden, soll zunächst nicht stören. Aufgabe 25: Überführen Sie auch dieses Programm in die objektorientierte Form (Trennung GUI – Fachkonzept). Erstellen Sie bitte zunächst die Klassendiagramme. Informieren Sie sich bitte hinsichtlich folgender VBA – Möglichkeiten: Die Tabelle soll in einem sogenannten Listfeld ausgegeben werden und die Zahlen sind zu formatieren. 58 Hinweise zur Codierung mit Listfeldern: Ist die ListBox zur Aufnahme aller Daten zu klein, wird automatisch eine Bildlaufleiste angelegt. Tilgungsplan.ListBox1.Clear While k > r z = (k * p) / 100 t = r - z k = k – t Eine zusätzliche Möglichkeit zur Codierung einer kopfgesteuerten Schleife: While … WEnd ………… If z < 100 Then a2 = " 00.00 Else If z < 1000 Then a2 = " 000.00 Else If z < 10000 Then a2 = " 0000.00 Else If z < 100000 Then a2 = " 00000.00 Else If z < 1000000 Then a2 = " 000000.00 Else a2 = "0000000.00 End End End End End If If If If If " " " " " " Dies ist eine Möglichkeit der Formatierung numerischer Werte, wenn ein Unterdrückung führender Nullen vorzunehmen ist, für den Tabellenaufbau aber Leerstellen zu berücksichtigen sind. Diese Prozedur wäre für alle Ausgabefelder einer Zeile anzuwenden, müsste aber zwecks einer sinnvollen Modellierung der Programmstruktur ausgelagert werden (z. B. Definieren einer Klasse „Ausgabenaufbereitung“. ListBox ………… Im Original: eine Zeile! Tilgungsplan.ListBox1.AddItem Format(j, a1) & Format(z, a2) & Format(t, a3) & Format(k, a4) j = j + 1 Wend 59 Aufgabe 26: Es ist ein Programm zu erstellen für den Druck einer Wertetabelle der Funktion y=x². Einzugeben sind sowohl Unter- und Obergrenze der Wertetabelle als auch die Schrittweite für die Berechnung der y-Werte. Welcher Schleifentyp erscheint Ihnen als der sinnvollste Typ? Testen Sie bitte alle Schleifentypen Programmerweiterung: Unsinnige Werte werden abgewiesen und eine Neueingabe verlangt. Aufgabe 27: Office-Programme für Tabellenkalkulation haben die Funktionen MIN(), MAX() und MITTELWERT(). Programmieren Sie diese Funktionen in VBA. Die Anzahl der Eingabewerte ist beliebig. Programmerweiterung: Bezüglich der Funktionen MIN() und MAX() wird auch noch ausgegeben, um die wievielte der eingegebenen Zahl es sich handelt (Position der Zahl auf der Eingabeliste). 60 Prozeduren und Funktionen (Ergänzungen) Funktionen und Prozeduren sind ja bereits im Zusammenhang mit den Methoden eines Objektes bekannt. Beispiel (hier unabhängig von einer Klasse): Sub funkt_test() Dim a As Integer Dim b As Integer a = 3 a = a + 6 b = Sqr(a) MsgBox ("Wurzel aus 9: " & b) End Sub Die Anweisungszeile a = a + 6 wird vom Compiler in Maschinensprache übersetzt und kann dann ausgeführt werden. Anders ist es bei der Zeile: b = Sqr(a) Das Berechnen der Quadratwurzel ist ein mathematisches Verfahren, welches als fertiges Programm von VBA zur Verfügung gestellt wird und praktisch für das vom Programmierer oder der Programmiererin erstellte Programm unsichtbar "irgendwo im Hintergrund" abläuft, wenn es mit seinem Namen Sqr aufgerufen wird. Solche Programme heißen Funktionen. Normalerweise gibt man ihnen etwas mit: Übergabewerte, Schnittstelle, Funktionsargumente, Parameter (hier die Variable a, aus der die Wurzel berechnet werden soll) und sie liefern etwas zurück Rückgabewert, Return-Wert (hier den Wert der Quadratwurzel aus a, der dann in der Variablen b gespeichert wird). Funktionen werden aber nicht nur von VBA bereitgestellt, sie lassen sich auch selbst programmieren (siehe z. B. die Methoden von Objekten). Ein Beispiel: Sub Dim Dim Dim Dim m_test() a As Double b As Double c As Double m As Double a = 4.3 b = 5.5 c = 17.2 m = mit(a, b, c) MsgBox ("Mittelwert: " & m) End Sub Function mit(x As Double, y As Double, z As Double) As Double mit = (x + y + z) / 3 End Function 61 Erklärung: Das Programm m_test ruft die Funktion auf und übergibt ihr Daten, die sie zur Verarbeitung benötigt: mit(a, b, c) Die Festlegung der Schnittstelle und des Rückgabewertes wird folgendermaßen vorgenommen: Function mit(x As Double, y As Double, z As Double) As Double Die Funktion mit dem Namen mit gibt einen Wert vom Typ double zurück Name der Funktion Parameter, die bei dem Funktionsaufruf an die Funktion übergeben werden, hier alle drei vom Typ double. Das Programm, welches die Funktion aufruft erhält auf folgende Weise den Rückgabewert: mit = (x + y + z) / 3 (in der Funktion mit) Das Programm kann den Wert dann selbst benutzen: m = mit(a, b, c) (im Programm m_test, welches die Funktion aufruft) Aufgabe 28: Testen Sie dieses Programm und erklären Sie wie es „funktioniert“! Berücksichtigen Sie bitte insbesondere diese Anweisungszeile in der Funktion: mit = (x + y + z). Prozeduren Prozeduren kennen Sie bereits, jedes Programm, welches Sie bisher geschrieben haben, ist eine Prozedur (= Ansammlung von Anweisungen), welche mit Sub eingeleitet wird und mit End Sub beendet wird. Im Prinzip ist die Arbeitsweise und der Aufruf von Prozeduren und Funktionen gleich, der Unterschied besteht darin, dass Prozeduren keinen Rückgabewert liefern. 62 Hier noch eine sehr nützlich Funktion, welche kaufmännisch rundet: Sub r_test() Dim a As Double Dim c As Double c = 17.2673 a = fRunden([c], 2) MsgBox ("Gerundete Zahl: " & a) End Sub Function fRunden(Z, St) As Double fRunden = Sgn(Z) * Int(Abs(Z) * (10 ^ St) + 0.5) / (10 ^ St) End Function 63 5. Algorithmen mit strukturierten Datentypen Neben den unstrukturierten Datentypen (Standard-Typen wie z. B. double) gibt es die strukturierten (konstruierten) Typen wie Array, Record und File. Arrays (Felder, Matrizen, Tabellen) Beispiel einer Problembeschreibung: Für eine statistische Berechnung ist es erforderlich, dass viele (z. B. 500) Zahlenwerte eingegeben werden und dass diese Werte für eine nach der Eingabe erforderlichen Berechnung alle im Hauptspeicher des Computers verfügbar ein müssen. Es ist einsichtig, dass eine Deklaration eines jeden einzelnen Wertes sehr umständlich wäre, z. B.: Dim Dim Dim Dim Dim Dim Z1 Z2 Z3 Z4 Z5 Z6 As As As As As As Double Double Double Double Double Double u.s.w Dim Z500 As Double Für Problemstellungen dieser Art existiert eine wesentlich komfortablere Art der Datendefinition: Dim Z(500) As Double Gleiche Datentypen werden so zu sogenannten Datenfeldern (Arrays, Tabellen) zusammengefasst. Die einzelnen Elemente eines Arrays haben alle den gleichen Namen (hier: Z); unterscheiden lassen sie sich durch einen Index, der hinter dem Datennamen in Klammern steht. Bei der Deklaration wird die Anzahl der Datenelemente in der Klammer angegeben (in unserem Fall 500). Bei manchen Programmiersprachen wird das erste Element mit dem Index 0 (hier also Z(0)) angesprochen, andere Sprachen (z. B. COBOL) beginnen mit dem Index 1 für das erste Element, da dies etwas anschaulicher ist. VBA gestattet beides; soll mit den Index 0 begonnen werden, wird nichts angegeben, ansonsten erfolgt eine Option-Angabe: Option Base 1 Dim Z(500) As Double 64 Die folgende Abbildung veranschaulicht die Speicherung eines Arrays im Hauptspeicher: 3,4 12,7 1,67 78,41 1,44 45,0 usw Z(1) Z(2) Z(3) Z(4) Z(5) Z(6) usw Element 1 Element 2 Element 3 Element 4 usw Ein kleines Beispiel, hier aber mit String-Variablen als Basis-Datentyp, dient der Einführung in die Array-Thematik: Option Explicit Option Base 1 Sub Woche() Dim w_name(7) As String Dim i As Integer w_name(1) = "Montag" w_name(2) = "Dienstag" w_name(3) = "Mittwoch" w_name(4) = "Donnerstag" w_name(5) = "Freitag" w_name(6) = "Samstag" w_name(7) = "Sonntag" i = InputBox("Eingabe Wochentag (1-7)") MsgBox ("Tag: " & w_name(i)) End Sub Aufgabe 29: Testen Sie das Programm und erklären Sie bitte seine Funktionsweise! Was passiert, wenn als Wochentag eine Zahl größer 7 oder kleiner 1 eingegeben wird? Korrigieren Sie das Programm mit Hilfe einer geeigneten Abfrage und der Ausgabe einer Fehlermeldung bei falscher Eingabe! 65 Übung Finden Sie die Funktionalitäten des Programms mit der unten stehenden Bildschirmmaske heraus. Hilfe: Analysieren Sie den Quelltext. Option Explicit Dim w_name(7) As String Dim Umsatz(7) As Double Dim i As Integer Private Sub CommandButton1_Click() w_name(1) = "Montag" w_name(2) = "Dienstag" w_name(3) = "Mittwoch" w_name(4) = "Donnerstag" w_name(5) = "Freitag" w_name(6) = "Samstag" w_name(7) = "Sonntag" i = TextBox1 TextBox2 = w_name(i) TextBox3 = Umsatz(i) End Sub Private Sub CommandButton2_Click() i = TextBox1 Umsatz(i) = TextBox3 End Sub Private Sub CommandButton3_Click() TextBox1 = "" TextBox2 = "" TextBox3 = "" End Sub 66 Sortierung von Zahlen (Selection Sort) Problemstellung: Es werden Zahlen in beliebiger Reihenfolge eingegeben; die Anzahl ist festgelegt (z. B. 10). Die Zahlen sollen der Größe nach aufsteigend sortiert und dann ausgegeben werden. Hinweis: Die eingegebenen Zahlen (und die danach sortierten Zahlen) stehen in einem Array. Lösung: Es wird hier ein einfacher Sortieralgorithmus vorgestellt. Folgende Überlegungen liegen diesem zugrunde: 1. Zunächst muss die kleinste Zahl gesucht und an die erste Stelle des Array gebracht werden. 2. Das gleiche wird nun für die zweitkleinste Zahl und dann für die drittkleinste Zahl usw. durchgeführt. Der Überschaubarkeit halber wird hier nur von 4 Zahlen ausgegangen, die nach der Eingabe im Array stehen: 8 3 5 1 0 Z(1) Z(2) Z(3) Z(4) H Wenn zunächst die kleinste Zahl an den Anfang des Array geschoben werden soll, müssen alle Zahlen miteinander verglichen werden. Das Schieben bewirkt nun, dass das ursprüngliche Tabellenelement von einer anderen Zahl überschrieben und damit gelöscht wird. Aus diesem Grund existiert noch eine Variable H, eine Hilfsvariable, gleichsam ein Zwischenspeicher. Der Tausch funktioniert nun folgendermaßen: 1. Schritt: If Z(2) < Z(1) Then Z(2) und Z(1) vertauschen: Z(2) H, Z(1) Z(2), H Z(1) 3 8 5 1 3 Z(1) Z(2) Z(3) Z(4) H 67 2. Schritt: If Z(3) < Z(1) Then Z(3) und Z(1) vertauschen: Z(3) H, Z(1) Z(3), H Z(1) hier bleibt alles, wie es war, da die Bedingung nicht zutrifft: 3 8 5 1 3 Z(1) Z(2) Z(3) Z(4) H 3. Schritt: If Z(4) < Z(1) Then Z(4) und Z(1) vertauschen: Z(4) H, Z(1) Z(4), H Z(1) 1 8 5 3 1 Z(1) Z(2) Z(3) Z(4) H Jetzt steht in der Tat die kleinste Zahl an erster Stelle des Arrays. Das gleiche wird nun für die zweitkleinste Zahl durchgeführt. 4. Schritt: If Z(3) < Z(2) Then Z(3) und Z(2) vertauschen: Z(3) H, Z(2) Z(3), H Z(2) 1 5 8 3 5 Z(1) Z(2) Z(3) Z(4) H 5. Schritt: If Z(4) < Z(2) Then Z(4) und Z(2) vertauschen: Z(4) H, Z(2) Z(4), H Z(2) 1 3 8 5 3 Z(1) Z(2) Z(3) Z(4) H Jetzt steht die zweitkleinste Zahl an zweiter Stelle des Arrays. Das gleiche wird nun für die drittkleinste Zahl durchgeführt. 68 6. Schritt: If Z(4) < Z(3) Then Z(4) und Z(3) vertauschen: Z(4) H, Z(3) Z(4), H Z(3) 1 3 5 8 5 Z(1) Z(2) Z(3) Z(4) H Nun steht die drittkleinste Zahl an der dritten Stelle des Arrays und die höchste Zahl „automatisch“ an der letzten Stelle: das Array ist aufsteigend sortiert, das Verfahren ist beendet. selection_sort I = 1, MAX ist die Anzahl der Tabellenelemente, wird hier festgelegt solange bis I > MAX Eingabe Z(I) I=I+1 I=1 solange bis I > (MAX-1) K=I+1 solange bis K > MAX Z(K) < Z(I)? ja nein H=Z(K) Z(K)=Z(I) Z(I)=H ./. K=K+1 I=I+1 Ausgabe der Werte (Z(I)) Beachten Sie bitte: Hier ist eine innere Schleife (solange bis K > MAX) in eine äußere Schleife (solange bis I > MAX-1) "verschachtelt". 69 Aufgabe 30: Überprüfen Sie den Algorithmus anhand der Daten auf den vorherigen Seiten in Form eines Schreibtischtests (Schritt 1 bis Schritt 6)! Legen Sie bitte die zusätzlichen Variablen I und K an, MAX ist 4. Codierung: Option Explicit Option Base 1 Sub sel_sort() Dim Z(10) As Integer Dim I As Integer Dim K As Integer Dim H As Integer Dim aus As String For I = 1 To 10 Z(I) = InputBox("Wert: ", I) Next I For I = 1 To 9 For K = I + 1 To 10 If Z(K) < Z(I) Then H = Z(K) Z(K) = Z(I) Z(I) = H End If Next K Next I aus = "Sortierung: " For I = 1 To 10 aus = aus & Z(I) & " " Next I MsgBox (aus) End Sub Aufgabe 31: Erstellen Sie nun eine äquivalente Lösung dieses Problems mit einer DoWhile-Schleife! 70 Die Record-Struktur Bei der Festlegung der Strukturart Array werden Daten vom gleichen Datentyp zu einer größeren Einheit, dem Array (oder der Tabelle) zusammengefasst. Weitaus häufiger liegt aber in der Datenverarbeitung der Fall vor, dass Daten eine Einheit (einen Verbund) bilden, die nicht vom gleichen Datentyp sind. Beispiele solcher Datenstrukturen sind die Informationen, die zur Beschreibung von Kunden oder Artikeln benötigt werden: Kunde Kundennummer Name Straße PLZ Ort Telefon 6 Stellen 25 Stellen 25 Stellen 5 St. 30 St. 14 Stellen (alle vom Datentyp String, aber unterschiedlicher Länge) oder: Artikel Artikelnummer Bezeichnung Preis (EK) 6 Stellen, String 30 Stellen, String Double Preis (VK) Mengeneinheit Double Integer (Code) Wenn mit solchen sogenannten Record-Strukturen gearbeitet werden soll, wird (in dem meisten Programmiersprachen) dem Computer zunächst mitgeteilt, dass ein individueller (benutzerdefinierter) Datentyp mit einem komplexeren Aufbau zu vereinbaren ist. Diesem neuen Datentyp wird dann auch ein Name zugeordnet, den die Programmiererin oder der Programmierer selbst wählt. Beispiel: Type record_1 Anum As Integer Abez As String Apreis As Double End Type Der neu festgelegte Datentyp hat jetzt den Namen "record_1" (man hätte ihm selbstverständlich einen anderen Namen geben könne, z. B. datensatz_artikel). Damit wurde aber noch keine Variable deklariert (eben nur ein neuer Typ vereinbart, vergleichbar mit Double, Integer usw.). Im Programm wird nun eine Variable von diesem speziellen Datentyp deklariert. Beachte: Ein RECORD ist gleichsam eine Klasse ohne Methoden. 71 Dim Artikelsatz As record_1 Der Variablename lautet nun "Artikelsatz"; auf die einzelnen Komponenten der Variable (d.h. auf die einzelnen Daten) wird nun mit dem sogenannten PunktOperator zugegriffen: Artikelsatz.Anum Demo-Programm (Strukturart Record): Option Explicit Type record_1 Anum As Integer Abez As String Apreis As Double End Type Sub datensatz() Dim Artikelsatz As record_1 Dim I As Integer Dim aus As String Artikelsatz.Anum = InputBox("Artikelnummer: ") Artikelsatz.Abez = InputBox("Artikelbezeichnung: ") Artikelsatz.Apreis = InputBox("Artikelpreis: ") aus = "Artikelsatz: " With Artikelsatz aus = aus & .Anum & " " & .Abez & " " & .Apreis End With MsgBox (aus) End Sub Das Programm erfasst die einzelnen Daten zu dem Artikelsatz, baut anschließend einen Ausgabestring zusammen und gibt diesen zur Kontrolle aus. Mit der With-Anweisung wird der Punkt-Operator einschließlich des Variablennamens des Artikel-Datensatzes eingespart. Ausformuliert (ohne With...) lautet das Zusammensetzen des Ausgabestrings folgendermaßen: aus = aus & Artikelsatz.Anum & " " & Artikelsatz.Abez & " " & ... Aufgabe 32: Vereinbaren Sie den Record-Typ für den (etwas ausführlich beschriebenen) Artikel-Datensatz auf der vorherigen Seite! Deklarieren Sie eine Variable mit dem Namen A_Satz von diesem Typ (Codierung als „Modul“!). 72 Die Strukturart „Record“ kann selbst andere, benutzerdefinierte Strukturen beinhalten. Sie kann aber auch als Datenelement eines Arrays benutzt werden. In diesem Fall können mehrere (viele) Datensätze als Tabelle verarbeitet werden. Das folgende Beispiel verdeutlicht eine einfache Anwendung zu dieser Thematik. Im Prinzip repräsentiert dies bereits eine Datei mit mehreren Datensätzen. Erweitert um einen Abspeicherungsmechanismus und der Möglichkeit, die Datensätze wieder von der Festplatte zu laden, wäre das bereits ein Beispiel für eine einfache Dateiverarbeitung (s. später). Das folgende Beispiel demonstriert die Verbindung von Array und Record: Option Explicit Type record_1 Anum As Integer Abez As String Apreis As Double End Type Sub datensatz() Dim Artikelsatz(3) As record_1 Dim I As Integer Dim aus As String For I = 1 To 3 Artikelsatz(I).Anum = InputBox("Artikelnummer: ") Artikelsatz(I).Abez = InputBox("Artikelbezeichnung: ") Artikelsatz(I).Apreis = InputBox("Artikelpreis: ") Next I For I = 1 To 3 aus = "Artikelsatz " & I & ": " With Artikelsatz(I) .Apreis = .Apreis * 0.95 aus = aus & .Anum & " " & .Abez & " " & .Apreis End With MsgBox (aus) Next I End Sub Aufgabe 33: Analysieren Sie dieses Programm! Erstellen Sie ein Struktogramm und beschreiben Sie die Funktionsweise in Worten! 73 Dateiverarbeitung Eingabe von drei Datensätzen und Ausgabe in eine Datei: Option Explicit Private Type record_Artikel A_nummer As Integer A_bezeichnung As String A_preis As Double End Type Sub Dateiverarbeitung() Dim Artikeltabelle(3) As record_Artikel Dim I As Integer For I = 1 To 3 Artikeltabelle(I).A_nummer = InputBox("Artikelnummer: ") Artikeltabelle(I).A_bezeichnung = InputBox("Artikelbezeichnung: ") Artikeltabelle(I).A_preis = InputBox("Artikelpreis: ") Next I Open "Artikeldatei" For Output As #1 For I = 1 To 3 Write #1, Artikeltabelle(I).A_nummer, Artikeltabelle(I).A_bezeichnung, Artikeltabelle(I).A_preis Next I Close #1 End Sub Einlesen (Notwendige Zeilen von oben übernehmen): Open "Artikeldatei" For Input As #1 For I = 1 To 3 Input #1, Artikeltabelle(I).A_nummer, Artikeltabelle(I).A_bezeichnung, Artikeltabelle(I).A_preis Next I I = InputBox("Welcher Datensatz soll angezeigt werden? Nummer:") MsgBox (Artikeltabelle(I).A_nummer) MsgBox (Artikeltabelle(I).A_bezeichnung) MsgBox (Artikeltabelle(I).A_preis) Close #1 74 Dateiverarbeitung im Dialog Problem: Es sollen sich Daten zu verschiedenen Artikeln erfassen lassen, alle Daten können auf die Festplatte als Datei abgespeichert werden. Es besteht die Möglichkeit, die Datei wieder zu laden und die Artikeldaten in einem „BlätternModus“ anzuzeigen. Die Datensatzstruktur hat folgenden Aufbau: - Artikelnummer: Integer - Artikelbezeichnung: 20 Zeichen, String - Artikelpreis: Double Der Bildschirm ist folgendermaßen aufgebaut: Hinweise zur Problemlösung: Bei der hier formulierten Artikelverwaltung handelt es sich um die erste vereinfachte Version eines Programms, welches später hinsichtlich des Datenmodells und der Funktionen verbessert bzw. ausgebaut werden sollte. Im Fachkonzept ist ein Array zu vereinbaren; die einzelnen Array-Elemente bestehen aus Datensätzen (Datenstruktur RECORD). Maximal können (zunächst zu Testzwecken) 10 Datensätze erfasst und gespeichert werden. Die Datensätze werden durch Mausklick alle abgespeichert oder geladen, d.h. das ganze Array wird komplett geladen oder abgespeichert. Sämtliche Dateizugriffe erfolgen in der Fachkonzept - Klasse (hier. ZweiSchichten-Modell, sollte später zu dem 3-Schichten-Modell erweitert werden), die GUI „weiß“ also nicht, wie die Datenspeicherung erfolgt: Absolute Trennung zwischen Datenhaltung und GUI! 75 Aufgabe: Analysieren Sie bitte das vorliegende Programm vollständig! Zeichnen Sie die Klassendiagramme für das Fachkonzept und die GUI! Erstellen Sie eine Übersicht die darstellt, welche Funktionsblöcke/Moduln (hier: Prozeduren) vorhanden sind und wie sie zusammenhängen und zeichnen Sie die entsprechenden Struktogramme. Führen Sie ebenfalls eine Datenanalyse durch. Es ist wichtig, dass Ihnen der Programmablauf und die Bedeutung der Daten vollständig klar wird, damit in weiteren Arbeitsschritten dieses Programm erweitert werden kann! (Hinweis: Das Programm funktioniert fehlerfrei, es wurden allerdings nicht alle Plausibilitäten bzw. die Möglichkeiten des falschen Programmhandlings durch den Benutzer berücksichtigt!) UserForm: Option Explicit Dim oArtDat As clsArtDat Private Sub Aktualisieren_FeldEdit() TextBox4 = oArtDat.sn oArtDat.A_Nummer = TextBox1 oArtDat.A_Bezeichnung = TextBox2 oArtDat.A_Preis = TextBox3 End Sub Private Sub TextBox4 TextBox1 TextBox2 TextBox3 End Sub Aktualisieren_EditFeld() = oArtDat.sn = oArtDat.A_Nummer = oArtDat.A_Bezeichnung = oArtDat.A_Preis Private Sub CommandButton1_Click() oArtDat.Dat_oeffnen Aktualisieren_EditFeld End Sub Private Sub CommandButton2_Click() Aktualisieren_FeldEdit oArtDat.Dat_speichern End Sub Private Sub CommandButton3_Click() Aktualisieren_FeldEdit oArtDat.hole_Satz_prev Aktualisieren_EditFeld End Sub 76 Private Sub CommandButton4_Click() Aktualisieren_FeldEdit oArtDat.hole_Satz_next Aktualisieren_EditFeld End Sub Private Sub CommandButton5_Click() Set oArtDat = Nothing End End Sub Private Sub UserForm_Initialize() Set oArtDat = New clsArtDat oArtDat.sn = 1 TextBox1 = 0 TextBox2 = " " TextBox3 = 0# End Sub Klasse: Option Explicit Const max = 10 Private Type record_Artikel mA_nummer As Integer mA_bezeichnung As String mA_preis As Double End Type Private Artikeltabelle(max) As record_Artikel Private mI As Integer Private z As Integer Public Property Let A_Nummer(Num As Integer) Artikeltabelle(mI).mA_nummer = Num End Property Public Property Let A_Bezeichnung(Bez As String) Artikeltabelle(mI).mA_bezeichnung = Bez End Property Public Property Let A_Preis(Preis As Double) Artikeltabelle(mI).mA_preis = Preis End Property Public Property Get A_Nummer() As Integer A_Nummer = Artikeltabelle(mI).mA_nummer End Property Public Property Get A_Bezeichnung() As String A_Bezeichnung = Artikeltabelle(mI).mA_bezeichnung End Property 77 Public Property Get A_Preis() As Double A_Preis = Artikeltabelle(mI).mA_preis End Property Public Property Let sn(n As Integer) z = n End Property Public Property Get sn() As Integer sn = z If mI = 0 Then mI = 1 End Property Public Sub hole_Satz_prev() z = z - 1 If z < 1 Then z = 1 mI = z End Sub Public Sub hole_Satz_next() If z = 0 Then z = 1 z = z + 1 If z > max Then z = max mI = z End Sub Public Sub Dat_oeffnen() Open "h:\Artikeldateir" For Input As #1 For mI = 1 To max Input #1, Artikeltabelle(mI).mA_nummer, Artikeltabelle(mI).mA_bezeichnung, Artikeltabelle(mI).mA_preis Next mI Close #1 mI = 1 z = 1 End Sub Public Sub Dat_speichern() Open "h:\Artikeldateir" For Output As #1 For mI = 1 To max Write #1, Artikeltabelle(mI).mA_nummer, Artikeltabelle(mI).mA_bezeichnung, Artikeltabelle(mI).mA_preis Next mI mI = 1 Close #1 End Sub Hinweis: Bei der erstmaligen Anwendung Programm starten, auf „Speichern“ klicken (leere Datei wird angelegt und Programm beenden. Dann erneut starten und Daten erfassen. 78 Exkurs: Änderungsdienst: ACCESS-Objekte Grundidee: Die Datenhaltungsschicht ist für die Datenspeicherung, z. B. in einer Datenbank oder in einer Datei verantwortlich. In dem vorliegenden Beispiel (2Schichten-Architektur) erledigt dies die Klasse „clsArtDat“. Das Programm ist nun dergestalt zu verändern, dass das Konzept der Dateiverarbeitung durch eine Access-Datenbank ausgetauscht wird. Die GUI-Schicht darf natürlich „davon nichts merken“; wie die Daten abgespeichert werden, ist für sie „unsichtbar“. Eine einfache Lösung, auf Access-Datenbanken zuzugreifen, ist die Verwendung der DAO-Bibliothek (Objektbibliothek: Sammlung von Objekten welche ermöglicht, auf eine Access-Datenbank zuzugreifen). Achtung: Es gibt andere Möglichkeiten und die nun folgende Vorgehensweise muss eventuell auf neue Access-Versionen angepasst werden! Bekanntmachen der Bibliothek: Zuerst: dann: 79 Neue Klasse mit DB-Zugriff: Option Explicit Const max = 10 Private Type record_Artikel mA_nummer As Integer mA_bezeichnung As String mA_preis As Double End Type Private Private Private Private Artikeltabelle(max) As record_Artikel mI As Integer z As Integer SQL_Str As String Public Property Let A_Nummer(Num As Integer) Artikeltabelle(mI).mA_nummer = Num End Property Public Property Let A_Bezeichnung(Bez As String) Artikeltabelle(mI).mA_bezeichnung = Bez End Property Public Property Let A_Preis(Preis As Double) Artikeltabelle(mI).mA_preis = Preis End Property Public Property Get A_Nummer() As Integer A_Nummer = Artikeltabelle(mI).mA_nummer End Property Public Property Get A_Bezeichnung() As String A_Bezeichnung = Artikeltabelle(mI).mA_bezeichnung End Property Public Property Get A_Preis() As Double A_Preis = Artikeltabelle(mI).mA_preis End Property Public Property Let sn(n As Integer) z = n If mI = 0 Then mI = 1 End Property Public Property Get sn() As Integer sn = z End Property Public Sub hole_Satz_prev() z = z - 1 If z < 1 Then z = 1 mI = z End Sub Public Sub hole_Satz_next() If z = 0 Then z = 1 z = z + 1 If z > max Then z = max mI = z End Sub 80 Public Sub Dat_oeffnen() Dim docNew As Document Dim dbWG As DAO.Database Dim rdArtikel As Recordset Dim intRecords As Integer Set dbWG = OpenDatabase(Name:="C:\BBST.mdb") Set rdArtikel = dbWG.OpenRecordset("Artikel", dbOpenDynaset) mI = 1 Do While Not rdArtikel.EOF Artikeltabelle(mI).mA_nummer = rdArtikel!ANummer Artikeltabelle(mI).mA_bezeichnung = rdArtikel!Bezeichnung Artikeltabelle(mI).mA_preis = rdArtikel!Preis rdArtikel.MoveNext mI = mI + 1 Loop dbWG.Close mI = 1 z = 1 End Sub Public Sub Dat_speichern() Dim docNew As Document Dim dbWG As DAO.Database Dim rdArtikel As Recordset Dim intRecords As Integer Set dbWG = OpenDatabase(Name:="C:\BBST.mdb") Set rdArtikel = dbWG.OpenRecordset("Artikel", dbOpenDynaset) mI = 1 For mI = 1 To max SQL_Str = "INSERT INTO Artikel(ANummer, Bezeichnung, Preis)" _ & " Values(" & Artikeltabelle(mI).mA_nummer _ & ", '" & Artikeltabelle(mI).mA_bezeichnung _ & "', " & Artikeltabelle(mI).mA_preis & ")" If Artikeltabelle(mI).mA_Nummer > 0 Then dbWG.Execute SQL_Str Next mI mI = 1 Close #1 End Sub 81 6 EXCEL - Objekte In diesem Teil geht es nun darum, mit Hilfe von VBA-Programmen EXCELTabellenblätter, Arbeitsmappen, einzelne Zellen oder Zellbereiche zu verändern. Dies bedeutet, dass Objekte manipuliert werden. Objekte (also z. B. eine einzelne Zelle) besitzen Eigenschaften (z. B. Größe, Farbe usw.) und Methoden, mit denen das Verhalten eines Objektes bestimmt wird (z. B. bewirkt die Methode Close einer Arbeitsmappe, dass dieses Objekt geschlossen wird. Wichtige Objekte: Application (Das gesamte EXCEL-Fenster) Workbook (eine Arbeitsmappe) Worksheet (das einzelne Arbeitsblatt) Range (Zellenbereich oder einzelne Zelle) Soll jetzt ein Zellenbereich manipuliert werden, ist folgender Zugriff darauf möglich: Workbooks(„MappeX“).Worksheets(„TabelleY“).Range(„A1:C5“) Wichtige Objekteigenschaften: Caption (Beschriftung der Objekte) Name Selection (das markierte Objekt) Value (Wert/Inhalt, z. B. einer Zelle) Sub zelle_fuellen() Workbooks(1).Worksheets(2).[B3].Value = "Hier bin ich!" End Sub Container-Objekt: Arbeitsmappe Objekt im Containerobjekt: Tabelle 2 82 Wichtige Objektmethoden: Activate (aktiviert ein Objekt, gleicher Effekt, wie das Anklicken mit der Maus) Clear (löschen) Cells (Zugriff auf spezielle Zellen, Cells erwartet eine Zeilen- und Spaltenindex) Close (Applications-Objet oder Arbeitsmappe schließen) Open (Arbeitsmappe öffnen) Einfaches Beispiel: Einer Excel-Zelle mittels VBA einen Wert zuweisen: Nach der Ausführung (F5): Beachten Sie diese Angaben (s. Quellcode oben)! 83 Beispiel 1. Schritt: Anlegen der folgenden Tabelle: Hinweis: „Tabelle1“ heißt nun Artikelliste. 2. Schritt: Geben Sie bitte folgenden Programmcode ein: Sub Artikel_suchen() ThisWorkbook.Sheets("Artikelliste").Activate ActiveSheet.[A1].Select Nummer_ein: Nr = InputBox("Bitte eine Nummer eingeben") If Not IsNumeric(Nr) Then MsgBox "Bitte nur eine Zahl!" GoTo Nummer_ein End If 84 Nr = Val(Nr) ActiveCell.Offset(0, 0).Select While ActiveCell.Value <> "" If ActiveCell.Value = Nr Then ActiveCell.Offset(0, 1).Select MsgBox "Der Artikel mit der Nummer " & _ Nr & " lautet " & ActiveCell.Value Exit Sub End If ActiveCell.Offset(1, 0).Select Wend MsgBox "Die Nummer " & Nr & " wurde nicht gefunden!" End Sub 3. Schritt: Starten Sie das Programm mit F5. Geben Sie in der InputBox eine Artikelnummer ein. Ist der dazugehörende Artikel vorhanden, müsste folgende Ausgabe erscheinen: Select-Methode: markiert eine Zelle oder einen Zellbereich Activate-Methode: macht eine einzelne Zelle zur aktiven Zelle Offset: Bereich versetzen (s. Excel-Hilfe) 85 Übungen Demoprogramm für verschiedene Möglichkeiten der Zellenbestimmung 1 2 3 4 5 6 7 8 9 10 11 Sub c() Dim x As Integer Dim y As Integer x=3 y=4 ActiveCell.Value = "56" Workbooks("Mappe1").Worksheets("Tabelle2").Range("C3").Value = 45 Workbooks("Mappe1").Worksheets("Tabelle3").Select Cells(x, y).Select ActiveCell.Value = "10120" End Sub Zeile 6: In der gerade aktivierten Tabelle wird in der markierten Zelle der Wert 56 eingetragen (könnte also an einer „zufälligen“ Zelle eingetragen werden) Zeile 7: Der „Zufall“ wird „ausgeschaltet“: Genau in Tabelle 2 in der Zelle C3 erscheint der Wert 45 Zeile 8: Tabelle 3 auswählen Zeile 9: Die in den Zeilen 4 und 5 mit Werten versehenen Variablen dienen nun zur Bestimmung der Zellen: x steht für die Zeile, Y für die Spalte Zeile 10: Zuweisung des Wertes 10120 an die durch die Zeilen 4,5,8,9 bestimmte Zelle 86 Beispiel: Die Werte der Funktion y = x² von VBA nach Excel bringen Option Explicit Sub c() Dim x As Integer Dim i As Integer x = 1 i = -5 Workbooks("Mappe1").Worksheets("Tabelle1").Select Do While i < 6 Cells(x, 1).Select ActiveCell.Value = i Cells(x, 2).Select ActiveCell.Value = i * i x = x + 1 i = i + 1 Loop End Sub 87 Aufgabe 34: Erweitern Sie das Programm bitte um folgende Möglichkeiten: 1. Die Tabelle hat eine Beschriftung. 2. Über InputBox können die Anfangs- und Endewerte für x eingegeben werden. 3. Es ist möglich, eine Schrittweite <> 1 zu wählen. 4. Unsinnige Eingabewerte werden abgefangen. Alles soll von VBA aus realisiert werden. Erstellen Sie mit dem Diagramm-Assistenten eine xy-Darstellung der Funktion! Beachten Sie: Bei Änderung der Werte ändert sich der Funktionsgraph automatisch. Hinweis: Unter Extras/Makro ist das VBA-Programm unter dem namen hinter Sub eingetragen, von hier aus kann es direkt (ohne <Alt> <F11>) gestartet werden. Das Arbeiten mit Dialogen und Formularen in EXCEL 88 Aufgabe 35: Erstellen Sie ein Dialogfenster ähnlich wie das auf der vorherigen Seite! Wenn Sie das Dialogfenster fertigerstellt haben, machen Sie bitte einen Doppelklick auf den Button „Werte berechnen“. Sie gelangen dann in den Quelltext Editor für dieses Dialogfenster. Ergänzen Sie bitte folgenden Quellcode: Private Sub CommandButton1_Click() Dim x As Integer Dim i As Integer Dim k As Integer Dim m As Integer m = 0 x = 1 i = UserForm1.TextBox1.Value k = UserForm1.TextBox2.Value + 1 If -(i) + k > 21 Then m = 99 If i > k Then m = 99 If m > 0 Then MsgBox ("Werte ungültig") Else Workbooks("Mappe1").Worksheets("Tabelle1").Select Do While i < k Cells(x, 1).Select ActiveCell.Value = i Cells(x, 2).Select ActiveCell.Value = i * i x = x + 1 i = i + 1 Loop End If End Sub 89 Erstellen Sie bitte unter Einfügen/Modul ein Modul und fügen Sie folgenden Quelltext dort ein: Sub parabel() UserForm1.Show End Sub Damit wird das Dialogfenster aktiviert, wenn Sie diese Sub unter Extras/Makro aufrufen. Nun können Sie mit dem Dialog arbeiten. Geben Sie bitte zuerst die Werte –10 und 10 ein. Damit legen Sie für das Diagramm die maximale Anzahl der darzustellenden Werte fest. Erstellen Sie nun das Diagramm (XY - Darstellung). Löschen Sie die Wertetabelle. Wenn Sie nun die Sub unter Extras/Makro erneut aufrufen und andere Werte eingeben werden Sie feststellen, dass sich der Funktionsgraph entsprechend ändert. Aufgabe 36: Modifizieren Sie bitte die vorliegende Lösung im Sinne der Trennung von GUI und Fachkonzept! Aufgabe 37: „Verschönern“ Sie bitte die Darstellung (Überschriften usw.). Programmieren Sie bitte das automatische Löschen der alten Funktionswerte, bevor die neuen ausgegeben werden! Aufgabe 38: Entwickeln Sie bitte ähnliche Programme für andere Funktionen und Funktionsgraphen. Suchen Sie bitte aus den früheren Aufgaben dieser Unterlagen geeignete Aufgaben für die Programmierung mit Dialogfenstern heraus. 90