Ein Beispiel aus der Praxis. Was wir im Rahmen dieser Dokumentation darzustellen beabsichtigen ist eine kleine, softwaretechnische Problemstellungsanalyse, die als Anregung für den Entwurf eigener Applikationen verstanden werden sollte. 1. Vorwort Wir schreiben das Jahr 1999. In der Abteilung eines hiesigen Großkonzerns herrscht die Goldgräberstimmung. Der Grund hierfür ist die Einführung der neuen Version des SAP-Produktes, des betriebswirtschaftlichen Software-Systems R/3 [1] für die Client/Server-Architekturen. Ein neues Release bringt diverse Ergänzungen und Erweiterungen des Funktionsumfanges der R/3-Technologie mit sich, dies bedeutet neue Werkzeuge für den Anwender, aber auch neue Schnittstellen des Systems mit seiner Umgebung. Zeitgleich beginnt der Wandel in den Köpfen der Anwender, insbesondere in denen der IT-Verantwortlichen. Die Handhabung der im SAP R/3-System hinterlegten Informationen darf nun – aus der Sicht der Benutzer – anpassungsfähiger werden. Dies bedeutet hier, dass die abteilungsspezifischen Informationen fachkräftebezogener aufbereitet werden. Zahlreiche bekannte, abteilungsinterne Geschäftsregeln der Datenauswertung und der Informationsverknüpfung müssen nun so in die EDV-Landschaft eingebetet werden, dass sie
Die Entscheidung für den Kauf, den Einsatz und die Erzeugung eines Software-Systems bleibt selten einer sachlichen Natur. Die bei der Entstehung der in dieser Unterlage behandelten Anwendung herrschenden politischen und soziokulturellen Aspekte wollen wir aber nicht näher betrachten. Was wir im Rahmen dieser Dokumentation darzustellen beabsichtigen ist eine kleine, softwaretechnische Problemstellungsanalyse, die als Anregung für den Entwurf eigener Applikationen verstanden werden sollte. 2. Der Kontext – die Softwaretechnologie und die Datenverarbeitung Das SAP R/3-System dient unserer Anwendung als primäre Datenquelle. Aus dieser Datenquelle werden definierte, abteilungsbezogene Fakten entnommen und der Datenbank [2] (Abb. 1 ) - nach dem Durchlauf von Datenprüffiltern - hinzugefügt. Diese Datenbank ist Bestandteil des in dieser Unterlage betrachtenden Systems und bildet unsere sekundäre Datenquelle.
Wesentlich für die Überlegungen, die wir anstellen wollen, ist die Tatsache, dass wir mit relativ großen Datenmengen arbeiten müssen. Grossen Datenmengen im Sinne einer Visual Basic-Anwendung, die für Informationsverarbeitung dieser Intensität nicht konzipiert ist. Das System wird täglich mit 60.000 – 80.000 Datensätzen angereichert, wobei viele davon aufgrund den zwischen ihnen fehlenden Datenbeziehungen [3] und auf sie einwirkenden Filterregeln die Datenbank nicht erreichen. Ein weiterer, wesentlicher Anteil der Datensätze bringt ausschließlich Wertänderungen [4] in der Datenbank unseres Systems mit sich, sodass wir nie mit einem Datenzuwachs dieser Größenordnung direkt in unserer sekundären Datenquelle zu rechnen haben. Aufgrund der beim Aufbau dieses Systems gemachten Erfahrungen – Datenverarbeitungszeiten im Netzwerkbetrieb von ca. 8 Stunden – lässt sich behaupten, dass wir uns quasi am Rande des mit VB Machbaren bewegen und an die Grenzbereiche einer schlichten EDV-Anwendung stoßen. Die Kopplung unseres Systems an die sekundäre Datenquelle – die Datenbank – erfolgt mittels ADO-Technologie, wie aus der Abb. 1 ersichtlich. Wie zu Beginn bereits erwähnt, wollen wir mit Hilfe unserer Software den Wünschen der Anwender gerecht werden, dies geschieht hier, indem wir eine Datenauswertungseinheit mit einem mächtigen Filter ausstatten, der die – für den jeweiligen Benutzer - relevanten Informationen der Datenbank durchsiebt. 2.1 Die Problematik – der prototypische Softwareentwurf vs. Komplexität Die Filtereinheit der Anwendung soll die Anforderungen diverser Berufsgruppen der Firma an die Datenauswertung erfüllen, d.h., die Datenabfrageeinheit der Software muss ihnen ein breites Spektrum an Suchoptionen anbieten.
Ein breites Spektrum an Suchoptionen für den Anwender - was heißt das für den Systementwickler? Es müssen diverse, zum Teil sehr umfangreiche Datenabfrageanweisungen (SQL) realisiert werden, da wir i.d.R. mehrere Tabellen der Datenbank gleichzeitig ansprechen und analysieren müssen. Dabei werden die Datenabfrageanweisungen vom Anwender mit - über die Filtereinheit (siehe Abb. 2) gesetzten – Parametern versehen. Vorspann: mit dem Aufbau des Datenfilters für unsere Anwendung befinden wir uns mitten in einem prototypischen Entwicklungsprozess. Prototypisch [5], da die Software aufgrund von Erfahrungen, die mit den einzelnen Versionen des Systems gemacht worden sind und den sich aus ihnen ergebenden neuen Fragestellungen für die Praxis fortentwickelt wird. Prototypisch bedeutet hier, dass die Entwicklung des Filters nicht auf eine exakt festgelegte Anwendungslogik aufbaut, die vom Kern – der vorhandenen Logik des Programms – bis hin zur Schale - der Anwendungsoberfläche - führt, sondern hier die entgegengesetzte Richtung einschlägt. Zuerst entsteht – in Absprache mit den Endanwendern – die Systemschale, die Anwendungsoberfläche (siehe Abb. 2 ), die den Anforderungen der Benutzer entspricht. Anschließend wird mittels Analyse der sich daraus ergebenden Anforderungen an das System die Datenabfrage für die Datenbank und die Logik der Anwendung definiert. Ein breites Spektrum an Suchoptionen dem Benutzer anbieten zu wollen bedeutet für uns in erster Linie den Aufbau einer anwenderorientierten, kompakten und somit auch komplexen Benutzerschnittstelle (vgl. Abb. 7). In einem prototypischen Entwicklungsprozess wird das Programm quasi zu einem Experiment, womit sich unkompliziert in die Bereiche vorstoßen lässt, die bei der Planung nicht berücksichtigt werden konnten, da sie nicht bekannt und/oder vollständig ergründet worden sind. Prototypischer Softwareentwicklungsprozess bedeutet ggf. aber auch, dass vorhandene Softwarebestandteile aufgrund neuerer Erkenntnisse verworfen werden. Ein enormes Maß an Weitblick wird benötigt, um die zu realisierenden Programmbausteine so allgemein zu gestalten, dass sie auch nach der Erlangung neuester Erkenntnisse über den (hier wirtschaftlichen) Bereich – obgleich abgewandelt – weiterverwendet werden können. Die hieraus resultierenden Konsequenzen? Wir befassen uns einerseits mit der Gestaltung einer komplexen Benutzerschnittstelle, die gemäß den Anforderungen der Anwender definiert worden ist. Andererseits müssen wir uns wiederum mit dem Gedanken anfreunden, dass u.U. „nichts bleibt, wie es ist“. Der mögliche Wandel der Systemlogik und der Form der Systemoberfläche bleibt stets - aufgrund des prototypischen Entwicklungsprozesses - zu berücksichtigen. An dieser Stelle an die Objektorientierung zu denken könnte sich als utopisch erweisen. Warum? Die Grundlage für eine objektorientierte Softwareentwicklung bildet i.A. ein durchdachtes, objektorientiertes Schema, z.B. ein UML-Diagramm, setzt aber voraus, dass die Grenzen des Systems bereits festgelegt und bindend sind. Wenn wir davon ausgehen, dass der Programmierer und der System-Designer wie in diesem Falle dieselbe Person sind und annehmen, dass unser Software-Prototyp permanent weiterentwickelt wird, stellen wir schnell fest, dass der Verwaltungsaufwand, ein bereits vorhandenes UML-Diagramm zu restrukturieren, enorm hoch ist. Den Aufwand, den wir anstellen müssen, um stets „up to date“ zu sein, steht nicht in einem ökonomisch sinnvollen Verhältnis zu unserer eigentlichen Programmierarbeit. Wie groß ist die Wahrscheinlichkeit, dass das momentan erzeugte Dokumentationsdiagramm in einigen Minuten, Stunden oder Tagen wieder verworfen wird? Die Chancen für die vollständige Erhaltung des Diagramms in unserem prototypischen Entwicklungsprozess sind gering. Aus diesem Grunde befassen wir uns an dieser Stelle mit einem nicht-objektorientierten Softwareentwurf.
3 Die Mittel gegen die Komplexität der Aufgabenstellung In einem Block unterhalb der Tabulatorseiten des Filters (siehe Abb. 2 ) finden wir fünf Tasten (Leistung, Umsatz,... Tag,...) die der Auswahl von mehreren logischen Informationsquellen dienen (vgl. Abb. 3 ). Diese Informationsquellen sind physikalisch innerhalb der Datenquelle hinterlegt. Wir bezeichnen ab jetzt die fünf Tasten als den Datenquellenschalter. Welchem Zweck dient er? In der Abb. 3 wurde die Datenquelle mit dem Datenbanksymbol versinnbildlicht. Sie beinhaltet sechs voneinander getrennte jedoch sich inhaltlich überschneidende Informationsmengen – die sechs gelben Balken in der Darstellung sollen die sechs möglichen Schalterstellungen andeuten. Jede dieser Informationsmengen enthält Spalten – ähnlich der[a1] einer Tabelle - die mit den Auswahlfeldern unseres Filters (Abb. 2 ) korrespondieren, d.h. mit diesen verknüpft sind. Ein Auswahlfeld bezieht sich dabei nicht nur auf eine, sondern auf mehrere dieser Informationsmengen. Aktiviert nun der Anwender eine Auswahlliste in der Maske, um darin einen Wert für die Datenabfrage auszuwählen, „weiß“ das System nicht, auf welche dieser sechs Informationsmengen sich die Suchabfrage zu beziehen hat. Aus diesem Grunde wählt der Benutzer über den Datenquellenschalter (Abb. 3 ) zuvor die entsprechende Informationsmenge aus.
Die Oberfläche des Filters - Abb. 2 – besteht nicht nur aus einer, sondern, wie an den Tabulatorlaschen erkennbar, aus mehreren Seiten. Die Informationsmengen sind daher mit mehreren Tabulatorseiten des Filters verknüpft. Wird eine bestimmte Informationsmenge ausgewählt, so werden die in dieser Menge vorhandenen Spalten mit den entsprechenden Auswahlfeldern des Filters verbunden. Verschiedene Mengen enthalten ggf. verschiedene Informationsspalten, so dass nicht alle Auswahlfelder auf einmal mit Informationen verbunden sein müssen. Werden sie nicht verbunden, so bieten sie dem Benutzer keine Daten zur Auswahl an. Damit der Anwender durch ein datenloses Auswahlfeld nicht verwirrt wird, wird das Feld deaktiviert [6]. Sechs Informationsmengen stehen uns zur Verfügung, folglich gibt es sechs Muster, nach denen die Felder ein-/ausgeblendet werden. Wir befinden uns mitten in einem prototypischen Entwicklungsprozess, daher können wir nicht davon ausgehen, dass wir
3.1 Die Visualisierung Irgendwann kommen wir bei der gegebenen Aufgabenstellung an einen Punkt, an dem wir zwar die Anforderungen erfasst haben, aber nicht wissen, WIE wir die Komplexität der Zusammenhänge zwischen den einzelnen Teilaufgaben organisieren sollen. IRGENDWIE als Leitwort bei der Realisierung der Software erweist sich spätestens dann als eine Einbahnstrasse, wenn wir die Korrektheit unserer Vorgehensweise beweisen müssen, bzw. das System erweitert werden soll. Wie also können wir uns selbst helfen? "Bei jeder geistigen Arbeit braucht man irgendwann Papier und Bleistift [...] sonst verlieren wir den Überblick" "Wir erfassen beim ersten ‚Hindenken’ in aller Regel nicht den Grundstein des zu errichtenden Gedankengebäudes, wir beginnen bei den Gedankengebäuden nicht mit dem Fundament, sondern vielleicht mit dem dritten Stock des Westflügels." [Weiler, 39 ff.] Der Schlüssel hierzu kann die Visualisierung (vgl. Abb. 4) und die ggf. darauf beruhende Modellbildung sein.
Es bietet sich an, Hilfskonstruktionen aufzubauen, die die Gesamtheit aller denkbaren Merkmale des Problems auf die wesentlichen Merkmale reduzieren. „Dabei wird das Originalsystem einer Systemanalyse unterzogen, bei der die wesentlichen Elemente des Systems, ihre Beziehungen zueinander und ihr Verhalten bestimmt wird. "Anschließend ist sicherzustellen, „dass das Modell in der Lage ist, das interessierende Verhalten des Originalsystems hinreichend genau wiederzugeben. Welche Abbildung geeignet ist, hängt maßgeblich vom Untersuchungszweck ab." [Sauerbier, 7] 3.2 Das Modell im Modell Die wissenschaftliche Methode zur Bekämpfung der Komplexität führt zur Modellbildung. Ein Datenbank-Modell oder ein Klassen-Modell in der objektorientierten Softwareentwicklung sind beide erprobte, wissenschaftliche Mittel einer organisierten, strukturierten Vorgehensweise bei der Erzeugung von Software. Wir haben uns bewusst gegen die objektorientierte Methode – die Klassenmodellbildung - entschieden, benötigen aber dennoch ein Modell, um der Komplexität der Aufgabenstellung zu begegnen. Wir möchten an dieser Stelle eine Nachbildung der Filtermaske kreieren, ein Filtermodell erschaffen, um die Aufgabe – mit Methode – zu lösen. Mit Methode heißt, dass wir planmäßig vorgehen wollen, d.h. wiederum, dass wir sicherstellen wollen, dass wir auch in der Lage sind, die Ergebnisse unserer Vorgehensweise zu prüfen. Eine Überprüfung unserer Vorgehensweise wird spätestens dann vonnöten sein, wenn wir unseren Software-Prototypen erweitern müssen.
Gemäß der Abb. 5 wollen wir ein logisches Gebilde erschaffen, eine „Zwischenschicht“ unserer Filter-Anwendung, die ein Modell der Filter-Oberfläche darstellt. Wie sieht die Modellbildung im Falle des Filters aus?
Vergegenwärtigt man sich, dass der Anwendung ein Datenbankmodell zugrunde liegt, das die Zusammenhänge zwischen den (rohen SAP R/3 -) Daten zum Ausdruck bringt und dass die Filtereinheit ein weiteres Modell darstellt, nämlich eines, das eine weitere Abstraktion der Daten für den Benutzer vornimmt – der Anwender bekommt ja diverse Zusammenfassungen der Spalteninformationen, die im Hintergrund geschehen nicht mit – so möchten wir die dritte Modellebene im Rahmen dieser Dokumentation erörtern. Aus der Abb. 7 lässt sich erkennen, dass die Tabulatorseiten des Filters zwar größtenteils aus den Auswahlfeldern (ComboBox-Objekte) bestehen, diese aber logisch unterschiedlich gruppiert und angeordnet sind. Zusätzlich finden wir einige in die Filtermaske integrierte Kontrollkästchen (CheckBox-Objekte).
Das Ziel unseres Modells – das wir nun konzipieren wollen - ist eine Vereinheitlichung der Objektgruppen im Hinblick auf die Eigenschaft Ein-/Ausblenden [7]. Wir möchten die Gruppen an Objekten über einen gewählten Index ansprechen dürfen. Warum? Wie bereits erläutert, wählt der User über den Datenquellenschalter eine der sechs Informationsmengen aus. Jeder dieser Mengen wird dabei ein Ein-/Ausblendmuster für die Feldaktivierung zugeordnet. Das System soll die Auswahlfelder, die keine Informationen enthalten werden, ausblenden. Dabei kann es auch vorkommen, dass Felder, die Informationen anbieten, bewusst dem Benutzer vorenthalten werden – eine Feldaktivierungslogik muss her. Wie werden die Objektgruppen bestimmt? Eine Objektgruppe wird über einen Rahmen [8] logisch zusammengefasst (vgl. Abb. 6 , Termine und Statusfelder) und/oder zusätzlich über einen Begriff neben dem Feld (Abb. 7) zum Ausdruck gebracht. Die roten dreidimensionalen Punkte in den Abbildungen sollen verdeutlichen, dass wir entweder bestimmte Feldergruppen – die Auswahl eines bestimmten Datums im Bereich von – bis, soll entweder als Einheit dem Anwender zur Verfügung gestellt werden oder gar nicht – oder aber einzelne Objekte verallgemeinern wollen. Anschließend sollen uns alle Objektgruppen als gleiche logische Einheiten im Rahmen des Programms zur Verfügung stehen (Abb. 8), da wir nicht ständig zwischen Auswahlfeld, Kontrollkästchen, Anzahl 1 oder Menge 2 unterscheiden möchten. Die Indizierung der Objektgruppen unseres Modells erfolgt hierbei mittels Konstanten oder der sog. "benannten Konstanten", die über die Enum-Anweisung definiert werden. Wie aus der Abb. 8 ersichtlich werden die Namen für die einzelnen Konstanten entsprechend den jeweiligen Gruppennamen gewählt, so dass wir über den, hinter der Bezeichnung einer Konstanten stehenden Wert, die Gruppe, die wir ansprechen möchten, gezielt auswählen können. Demnach wird der Aufruf von DoDatumAktiv(efBLT [9], True) den ersten Datumsblock bestehend aus zwei Auswahlfeldern aktivieren – siehe Enum in der Abbildung. Die genauere Definition des Moduls folgt in Kap. 4. Mit der Definition der benannten Konstanten (Abb. 8) haben wir uns für eine bestimmte Vorgehensweise entschlossen - nämlich die, der Erstellung eines Modells, das auf einem über Enum definierten Index basiert. Damit unser System normiert - ein einmal festgelegter Weg wird konsequent über alle Komponenten hinweg beibehalten - aufgebaut wird, definieren wir eine weitere benannte Konstante, die diesmal die Tabulator-Laschen konsequent abbildet (Abb. 9).
Ein Tabulatorobjekt [10] verfügt zwar bereits über eine Index-Eigenschaft, unser Ziel ist aber die Schaffung einer Einheitlichkeit im Rahmen unseres Systems. Die Ordnung stellt für uns das Mittel zur Bezwingung der Komplexität dar. Alle relevanten Filterkomponenten sollen mittels selbstdefinierter Index-Angaben angesteuert werden dürfen.
Unsere Datenquelle enthält drei Sorten an Daten, die jeweils als einzelne Datensätze (Einzelwerte) und kumuliert unter dem Gesichtspunkt Tagesdatum (Tag) zur Verfügung stehen. Wie eingangs bereits angedeutet, baut die Anwendung, aus der die Filterkomponente entstammt, auf einer fortgeschrittenen Form der Datenbanktechnologie auf, in der die Faktenredundanz gewollt und beabsichtigt ist, weil andere Aspekte der Datenverarbeitung – wie z. B. die Auswertungsgeschwindigkeit der Daten - im Vordergrund stehen. Aus der Abb. 3 erkennen wir, dass unsere genormte Vorgehensweise – der Einsatz von Definitionen der benannten Konstanten – konsequent weiterverfolgt wird, obgleich dort in einer fortgeschrittenen Variante. Bei 3 Datensorten zu je 2 Dimensionen ergeben sich kombinatorisch (3x2=) 6 Auswahlmöglichkeiten der Knopfbetätigung, diese werden als Konstanten zur Selektion der Informationsquelle innerhalb einer neuen Enum-Definition verankert. Wir möchten im Rahmen dieser Dokumentation jedoch nicht näher auf die Einzelheiten der Anwendung zugrundeliegenden Datenwelt eingehen, sondern widmen uns – wie bisher – dem Filtermodell. Wenn wir in einem Abstraktionsvorgang – gemäß der Abb. 8 – die logischen Gruppen von Objekten der Anwendungsoberfläche als logische Einheiten – die roten dreidimensionalen Punkte in den Graphiken – betrachten, können wir diese mit Hilfe eines Index gezielt selektieren.
Die Abb. 10 zeigt, nach welchen Kriterien die Zuordnung der Enum-Konstanten zu den Objekten der Anwendungsoberfläche erfolgt. Was geschieht hier? Somit sind z.B. die Konstanten efBLT bis efFAKTDATUM den logischen Gruppen zugeordnet, die sich auf die Datumsauswahl beziehen und somit aus je zwei Auswahlfeldern bestehen. Die Konstantenmenge eff bis efP bilden den Index für den Zugriff auf die Statusfelder, die in der Filteroberfläche durch ein CheckBox-Objekt realisiert werden, usw. Bis hierhin haben wir eine Menge mentaler Arbeit im Abstraktionsprozess geleistet. Wir haben erkannt, dass wir mit Objekten/Objektgruppen – wie sie auch definiert sein mögen – arbeiten wollen, daher haben wir uns die logischen Einheiten – 3D-Punkte in den Abbildungen – erdacht. Diese Objektgruppen – logische Einheiten - möchten wir gezielt ansprechen dürfen, womit die Definition eines Index – der Konstanten – sinnvoll wurde. Innerhalb des Index bzw. direkt an der Anwendungsoberfläche haben wir diverse Gruppen gleicher Objekttypen identifiziert (vgl. erneut Abb. 10 ) und somit eine Grundlage für die Definition des Modells unseres Filters geschaffen. Eine Grundlage für die Definition des Modells? Das Modell wird nun auf der Basis unserer bisherigen Erkenntnisse definiert, d.h. in eine Datenstruktur überführt. Die Abb. 11 liefert die Zusammenfassung dieser Informationen in einer graphischen Darstellung [12].
Von links nach rechts in der Graphik angedeutet entsteht somit ein Datensatz mit fünf Feldern. Die ersten drei Felder beinhalten – von oben nach unten betrachtet - drei Arrays [13] von denen wiederum das erste und das dritte Array Datensätze mit je zwei Feldern führen. In diesen Feldern befinden sich Verweise auf die Auswahlfelder der Maske (die extrem neugierigen schauen – bitte - unter Code 2 nach). Das zweite Array von oben besteht aus Verweisen auf die Oberflächenobjekte vom Datentyp CheckBox. Das vierte Feld wird von einem Datensatz gebildet, das zwei CheckBox-Objekte speichert, und das fünfte Feld ist ebenfalls ein Array, diesmal aber bestehend aus den gespeicherten Verweisen auf die Auswahlfelder. Für den Zugriff auf die Arrays des soeben definierten Modells nutzen wir den hierzu über Enum erzeugten Index (Abb. 10). Wie der Zugriff über den Index auf die Array-Felder des Modells erfolgt, demonstriert die Abb. 12 .
Bis hierhin haben wir ein Filter-Datenmodell kreiert, um die Verweise auf die Filteroberflächenobjekte darin zu speichern. Wir möchten die Objekte der Maske – wie bereits angekündigt – gezielt ein-/ausblenden und dies mit dem Hintergedanken, dass:
Die Datenstruktur, die für die Codierung der Ein-/Ausblendmusterinformationen herangezogen wird, könnte ein 2-dimensionales Array sein. In dem Falle ist es aber ein Array von Arrays, gem. Abb. 14 . Die Ursache hierfür war eine bestimmte Vorstellung, die sich bei mir eingestellt hat, das Bild einer „Perlenschnur“ - waagerecht, rot - an der die codierte „Logik“ für das Ein-/Ausblenden von Maskenobjekten – senkrecht, blau – wie an einer Halskette herunterhängt.
Wir nutzen die bereits zuvor besprochenen Enum-Mengen zur Indizierung der Arrays, die Informationen darüber enthalten sollen, OB das Objekt, das die Arrays modellieren, ein- oder ausgeblendet wird. Folglich ist der den Arrays zugrundeliegende Datentyp der Sorte Boolean. Was nun passieren muss ist folgendes:
4. Die Realisierung - Visual Basic 6.0 Die Ideen dürften sich problemlos in eine beliebige Programmiersprache übertragen lassen, da die Ansätze allgemeingültig sind. Die benannten Konstanten - Enum - finden ihre Anwendung sowohl in Visual Basic, als auch in Pascal, C++, C#, VB.NET, etc. Private Enum eFILTERBLATT eTERMIN eKUNDE eANDERE eINFORMATION eVERSION End Enum Public Enum eWObinICH eAE_Tag ' 0 eAE_Einzel eLE_Tag eLE_Einzel eUM_Tag eUM_Einzel eUNKNOWN ' Filter aus End Enum Private Enum eFAeinzel ' ALLE ! efBLT efLIEFIST efPLANstart efISTstart efPLANende efEROEFF efAE efFAKTDATUM eff efV efU efL efP efAUFTRGEB efREGUL efREMPF efIN efAUS efKURZBZCHN efVERTRIEB efBRANCHE efDISPON efTECHN efLAGEN efGRP efMASLAM efWIDERST efVERKBELEG efFAKTART efPPSAUFTRNR efSDAUFTRNR efMATNR End Enum Code 1: Konstantendeklarationen Code 1 zeigt noch einmal die Definitionen der besprochenen Konstanten der Abb. 9 und der mehrfach zum Einsatz kommenden Enum für die Indizierung der Objekte/Objektgruppen der Filtermaske eFAeinzel. Die besondere Aufmerksamkeit gilt der Konstanten eUNKNOWN deklariert als Public Enum eWObinICH. Im Rahmen der Implementierung wird u.a. eine Variable vom Typ eWObinICH definiert, die die aktuelle Auswahl des Benutzers mittels des Datenquelleschalters aufnimmt. Für die Zahlenwertvariablen in Visual Basic gilt, dass sie nach dem Start des Systems automatisch mit einer 0 initialisiert werden – was in vielen anderen Programmiersprachen nicht unbedingt der Fall sein muss und im Falle einer Enum-Variablen in VB auch nicht der Fall ist. Dies bedeutet, dass der Initialisierungszustand einer Enum-Variablen mit dem ersten Wert der Enum-Menge angedeutet wird, d.h., unsere Enum-Variable wird mit dem Wert eWObinICH.eAE_Tag initialisiert. Wir wollen aber mit Hilfe der Enum-Werte die sechs möglichen Benutzerentscheidungen – Auswahl der Informationsquelle 1 bis 6 – eindeutig kennzeichnen. Mit der automatischen Initialisierung unserer Variablen gibt das VB-Entwicklungssystem uns einen Wert vor, der nicht unbedingt der Benutzerauswahl entspricht. Versuchen wir nun das System im Debugger-Modus zu analysieren, so stoßen wir auf die vom VB-System "verfälschten" Informationen – verfälscht im Sinne einer unerwarteten Initialisierung der Enum-Variablen. Um dieser Problematik bewusst entgegenzuwirken, deklarieren wir eine weitere Konstante eWObinICH.eUNKNOWN, mit der wir auch – absichtlich – die Variable nach dem Start des Systems initialisieren. Auf diese Weise können wir die Systemzustände vollends kontrollieren und während der Analyse im Debugger-Modus auch sinnvoll darstellen. Private Type tDATUMBEREICH VON As ComboBox BIS As ComboBox End Type Private Type tARRDATA BZCHN As ComboBox NR As ComboBox End Type Private Type tLANDDATA IN As CheckBox AUS As CheckBox End Type Private Type tFILTER ' Modell des GESAMTEN Filters ! DATUM(eFAeinzel.efBLT To eFAeinzel.efFAKTDATUM) As tDATUMBEREICH STAT(eFAeinzel.eff To eFAeinzel.efP) As CheckBox ARR(eFAeinzel.efAUFTRGEB To eFAeinzel.efREMPF) As tARRDATA LAND As tLANDDATA DATA(eFAeinzel.efKURZBZCHN To eFAeinzel.efMATNR) As ComboBox End Type Private Type tDATAART ' Modell der Ein-/Ausblendmuster DATENART(eFAeinzel.efBLT To eFAeinzel.efMATNR) As Boolean End Type Private FILTER As tFILTER Private FILTERREGELN(eWObinICH.eAE_Tag To eWObinICH.eUM_Einzel) As tDATAART ' Globale Abbildung der Filterregeln ! Code 2: Datentypdefinitionen und Variablendeklarationen Im Abschnitt des Code 2 erfolgen die Definitionen der Datentypen für die Modellierung der Datensätze des Filtermodells, gem. Abb. 11, wie auch die Definition der Struktur des Modells selbst. Der Datentyp tDATUMBEREICH fasst die Referenzen – die Zeiger – auf zwei ComboBox-Felder der Filteroberfläche. Die Variablen VON und BIS in diesem Datensatz modellieren ein Pärchen an Auswahlfeldern, die der Anwender zur Festlegung eines Datumsbereiches in der Maske selektieren kann. Dieser Datensatz ist Bestandteil des ersten Arrays in der Abb. 11 und wird ebenfalls im Datenmodell, dem Datentyp tFILTER - Code 2 – als erstes Array abgebildet. DATUM(eFAeinzel.efBLT To eFAeinzel.efFAKTDATUM) As tDATUMBEREICH zeigt die Modellierung des gesamten Arrays. Dabei sind eFAeinzel.efBLT bis eFAeinzel.efFAKTDATUM die Indexwerte aus dem Enum eFAeinzel (Code 1), die benutzt werden, um die einzelnen Felder des Arrays zu erreichen. Auf analoge Art erfolgt die Abbildung weiterer Arrays und deren Datensätze im Modell unseres Filters. Der Datentyp tDATAART kapselt ein Array, das im Zusammenhang mit der Variablen Private FILTERREGELN(eWObinICH.eAE_Tag To eWObinICH.eUM_Einzel) As tDATAART, die "Logik" für das Ein-/Ausblenden der Oberflächenobjekte des Filters beinhaltet. Die Konstantenwerte eWObinICH.eAE_Tag bis eWObinICH.eUM_Einzel entsprechen hierbei den sechs Positionen, die den Anwender über den Datenquellenschalter erreichen kann – angedeutet in der Abb. 14 über die waagerecht angeordneten, roten Quadrate. Die Werte des Enum eWObinICH geben die Antwort auf die Frage "wo bin ich?". Der Benutzer soll dem System "erklären", wo er sich befindet, d.h. in dem Zusammenhang, mitteilen, welche der sechs Datenquellen angesteuert wird und welches der sechs Ein-/Ausblendmustern für die Aktivierung der Filterobjekte zu nutzen ist. Wir initiieren hier quasi den Benutzerlauschangriff "von unten", vom Innern des Systems. DATENART(eFAeinzel.efBLT To eFAeinzel.efMATNR) As Boolean – der Datentyp tDATAART ergibt die in der Abb. 15 senkrecht angeordneten, blauen Objekte, die für alle Objektgruppen an der Oberfläche des Filters stehen sollen. Zur Laufzeit des Programms wird diese Variable in einer Schleife von oben nach unter durchlaufen, womit überprüft wird – die Werte der Variablen sind vom Typ boolean – OB die jeweilige Gruppe an Objekten in der Maske des Filters angezeigt werden muss oder auch nicht.
Private FILTER As tFILTER definiert letztlich unter der Bezeichnung FILTER unser Filtermodell. Private Sub DoInitFilterMaske() DoInitArrayFilter ' Filterlogik ins Array eintragen... ' DoFilterRegelnProtokoll ' Fürs debuggen ! ' ------------------------------------------------------ ' Reale Objekte an das Filter-Modell zuweisen ! DoInitFilterDatum ' Die realen Objekte an das Modell der Maske zuweisen ! DoInitFilterRest ' ------------------------------------------------------ DoFilterLogikArrayToModel eLE_Tag ' default beim Start! ' Abbildung Array => Model End Sub Code 3: Das Initialisierungsmodul Das Initialisierungsmodul gem. Code 3 ruft nacheinander alle für eine sinnvolle Vorbelegung der Modelle – Filter und Ein-/Ausblendmuster - benötigten Quellcode-Einheiten auf. Zuerst wird die in Code 4 erläuterte Prozedur DoInitArrayFilter ausgeführt, mit der die sechs Ein-/Ausblendmuster mit Werten entsprechend der Auftraggeberanforderung vorbelegt werden. Danach wird die – im Bedarfsfalle einzusetzende – Prozedur DoFilterRegelnProtokoll wirksam. Sie dient der Ausgabe von Inhalten der Ein-/Ausblendlogik. Eine Erläuterung der Funktionsweise folgt in Kürze. Die Module DoInitFilterDatum und DoInitFilterRest dienen der Zuweisung der realen Objekte der Filteroberfläche unserem definierten Filtermodell. Schließlich übernimmt die Prozedur DoFilterLogikArrayToModel die Synchronisation der Ein-/Ausblend-logik mit dem Modell des Filter. ' Festhalten der Filterregeln im Array! ' Anschließend aktualisieren gemäß dieser Inhalte Private Sub DoInitFilterRegeln(ByVal ART As eWObinICH) With FILTERREGELN(ART) Select Case ART Case eWObinICH.eAE_Einzel .DATENART(eFAeinzel.efBLT) = True .DATENART(eFAeinzel.efLIEFIST) = False .DATENART(eFAeinzel.efPLANstart) = False .DATENART(eFAeinzel.efISTstart) = False .DATENART(eFAeinzel.efPLANende) = False .DATENART(eFAeinzel.efEROEFF) = False .DATENART(eFAeinzel.efAE) = True .DATENART(eFAeinzel.efFAKTDATUM) = False ' ------------- .DATENART(eFAeinzel.eff) = True .DATENART(eFAeinzel.efV) = True .DATENART(eFAeinzel.efU) = True .DATENART(eFAeinzel.efL) = True .DATENART(eFAeinzel.efP) = True ' ------------- Seite 2 .DATENART(eFAeinzel.efAUFTRGEB) = True .DATENART(eFAeinzel.efREGUL) = False .DATENART(eFAeinzel.efREMPF) = False .DATENART(eFAeinzel.efKURZBZCHN) = False ' .DATENART(eFAeinzel.efIN) = True ' .DATENART(eFAeinzel.efAUS) = True .DATENART(eFAeinzel.efVERTRIEB) = True .DATENART(eFAeinzel.efBRANCHE) = True .DATENART(eFAeinzel.efIN) = False .DATENART(eFAeinzel.efAUS) = False .DATENART(eFAeinzel.efVERTRIEB) = True .DATENART(eFAeinzel.efBRANCHE) = False .DATENART(eFAeinzel.efDISPON) = True ' ------------- Seite 3 .DATENART(eFAeinzel.efTECHN) = True .DATENART(eFAeinzel.efLAGEN) = True .DATENART(eFAeinzel.efGRP) = True .DATENART(eFAeinzel.efMASLAM) = True .DATENART(eFAeinzel.efWIDERST) = True .DATENART(eFAeinzel.efVERKBELEG) = True .DATENART(eFAeinzel.efFAKTART) = False .DATENART(eFAeinzel.efPPSAUFTRNR) = True .DATENART(eFAeinzel.efSDAUFTRNR) = True .DATENART(eFAeinzel.efMATNR) = True Case eWObinICH.eAE_Tag [...] Case eWObinICH.eLE_Einzel [...] Case eWObinICH.eLE_Tag [...] Case eWObinICH.eUM_Einzel [...] Case eWObinICH.eUM_Tag [...] End Select End With End Sub Code 4: Initialisierung der Ein-/Ausblendregeln In der Prozedur DoInitArrayFilter - Code 4 - wird eine Variable vom Enum-Typ eWObinICH deklariert. Sie dient als Iterationsvariable, um über die sechs möglichen, vom Benutzer festlegbaren Zustände zu iterieren, sie zu durchlaufen. Mit jedem Aufruf von DoInitFilterRegeln ii erfolgt eine Inkrementierung (Hochzählen) der Variablen . Dadurch wird das Modul DoInitFilterRegeln(ByVal ART As eWObinICH) sechs mal aufgerufen, jedes Mal mit einem anderen Variableninhalt, um jedes Mal einen anderen Zustand der Ein-/Ausblendlogik zu initialisieren. In der Prozedur DoInitFilterRegeln erfolgt der Zugriff auf die FILTERREGELN() einer bestimmten Art. In Abhängigkeit von der Art der Regeln - Select Case ART – wird entschieden, ob eine Objektgruppe für den Benutzer sichtbar bleibt - .DATENART(eFAeinzel.efBLT) = True – oder ausgeblendet sein soll - .DATENART(eFAeinzel.efLIEFIST) = False. Aufgrund der sprechenden Namensgebung für die benannten Konstanten, können wir dem Quellcode relativ leicht entnehmen, um welche Objektgruppen es sich hierbei handelt. Die Konstante efBLT steht für die Gruppe der Objekte, die sich auf den BLT-Termin [14] beziehen, wie aus der Abb. 15 ersichtlich. Die unter Code 5 dargestellte Code-Einheit DoFilterRegelnProtokoll dient uns als Testeinheit für die bereits im Logik-Modell mittels DoInitFilterRegeln hinterlegte Ein-/Ausblendlogik. Die Ausgabe der Ein-/Ausblendlogik-Informationen erfolgt dabei im Debug-Fenster, gem. Abb. 16. Private Sub DoFilterRegelnProtokoll() ' Test-Modul ! Dim ii As eWObinICH Dim nn As eFAeinzel For ii = eWObinICH.eAE_Tag To eWObinICH.eUM_Einzel Select Case ii Case eWObinICH.eAE_Einzel: Debug.Print "AE einzeln" Case eWObinICH.eAE_Tag: Debug.Print "AE tag" Case eWObinICH.eLE_Einzel: Debug.Print "LE einzeln" Case eWObinICH.eLE_Tag: Debug.Print "LE tag" Case eWObinICH.eUM_Einzel: Debug.Print "UM einzeln" Case eWObinICH.eUM_Tag: Debug.Print "UM tag" End Select For nn = eFAeinzel.efBLT To eFAeinzel.efMATNR With FILTERREGELN(ii) Select Case nn Case efBLT Debug.Print " -BLT => " & .DATENART(nn) Case efLIEFIST Debug.Print " -LiefIST => " & .DATENART(nn) Case efPLANstart Debug.Print " -PLANstart => " & .DATENART(nn) Case efISTstart Debug.Print " -ISTstart => " & .DATENART(nn) Case efPLANende Debug.Print " -PLANende => " & .DATENART(nn) Case efEROEFF Debug.Print " -EROEFF => " & .DATENART(nn) Case efAE Debug.Print " -AE => " & .DATENART(nn) Case efFAKTDATUM Debug.Print " -FAKTDATUM => " & .DATENART(nn) Case eff Debug.Print " -F => " & .DATENART(nn) Case efP Debug.Print " -P => " & .DATENART(nn) Case efV Debug.Print " -V => " & .DATENART(nn) Case efU Debug.Print " -U => " & .DATENART(nn) Case efL Debug.Print " -L => " & .DATENART(nn) Case efAUFTRGEB Debug.Print " -AuftrGeb => " & .DATENART(nn) Case efREGUL Debug.Print " -Regul => " & .DATENART(nn) Case efREMPF Debug.Print " -Rempf => " & .DATENART(nn) [...] Case efFAKTART Debug.Print " -FaktArt => " & .DATENART(nn) Case efMATNR Debug.Print " -MatNR => " & .DATENART(nn) End Select End With Next nn Next ii End Sub Code 5: Logik-Testmodul Dabei erzeugen wir – für jeden der sechs Zustände der Enum eWObinICH:
Wieso benötige ich ein Testmodul? Alternativ lässt sich die Information direkt dem Quellcode entnehmen. Wir müssen hierbei aber bedenken, dass wir uns im prototypischen Entwicklungsprozess befinden, in dem sich die Situation schnell ändern kann. Dementsprechend sollten wir in der Lage sein, die aktuelle Situation schnell zu erfassen und rasch zu dokumentieren. Indem wir die Ausgabe des Testmoduls in eine Datei statt an das Debug-Fenster umleiten, können wir die gespeicherten Logik-Zustände mit wenig Aufwand in einer dokumentierenden Unterlage bereitstellen. ' Verweise auf die Origilalobjekte sammeln ' => Zugriff über das Modell auf das Original Private Sub DoInitFilterDatum() With FILTER.DATUM(eFAeinzel.efBLT) Set .VON = Me.FldTERMBLTvon Set .BIS = Me.FldTERMBLTbis End With With FILTER.DATUM(eFAeinzel.efLIEFIST) Set .VON = Me.FldTERMLIEFISTvon Set .BIS = Me.FldTERMLIEFISTbis End With [...] With FILTER.DATUM(eFAeinzel.efFAKTDATUM) Set .VON = Me.FldTERMFAKTURAvon Set .BIS = Me.FldTERMFAKTURAbis End With End Sub ' Verweise auf die Origilalobjekte sammeln ' => Zugriff über das Modell auf das Original Private Sub DoInitFilterRest() With FILTER Set .STAT(eFAeinzel.eff) = Me.FldTERMStatusForecast Set .STAT(eFAeinzel.efP) = Me.FldTERMStatusPlan Set .STAT(eFAeinzel.efV) = Me.FldTERMStatusVorgabe [...] Set .DATA(eFAeinzel.efFAKTART) = Me.FldSONFAKTURAART Set .DATA(eFAeinzel.efMATNR) = Me.FldSONMatNr End With End Sub Code 6: Sammeln der Originalobjekte In den Prozeduren DoInitFilterDatum und DoInitFilterRest erfolgt die Zuweisung der Filterobjekte der Maske an das von uns definierte Filtermodell. ' Art mittels Knopfkombination bestimmt ! Private Sub DoFilterLogikArrayToModel(ByVal ART As eWObinICH) Dim ii As eFAeinzel With FILTERREGELN(ART) ' Art der Filterlogik ! For ii = eFAeinzel.efBLT To eFAeinzel.efMATNR Select Case ii ' Absteigend... Case eFAeinzel.efBLT To eFAeinzel.efFAKTDATUM DoDatumAktiv ii, .DATENART(ii) Case eFAeinzel.eff To eFAeinzel.efP DoStatusAktiv ii, .DATENART(ii) Case eFAeinzel.efAUFTRGEB To eFAeinzel.efREMPF DoArrAktiv ii, .DATENART(ii) Case eFAeinzel.efIN DoLandAktiv .DATENART(ii) Case eFAeinzel.efKURZBZCHN To eFAeinzel.efMATNR DoDataAktiv ii, .DATENART(ii) End Select Next ii End With End Sub Code 7: Synchronisationsmodul - Ein-/Ausblendlogik – Filtermodell DoFilterLogikArrayToModel bezieht sich auf die Übertragung der Ein-/Ausblendlogik auf das Filtermodell. Die Situation lässt sich aus der Abb. 15 entnehmen. Wir iterieren hierbei über die Logik-Arrays von oben nach unten – blau im Bild – und gleichen die Informationen mit den Modelldaten ab. Der Informationsabgleich erfolgt hierbei nur für einen bestimmten Fall, einen Fall, den der Benutzer durch die Betätigung des Datenquellenschalters bestimmt hat – Parameter ART, vom Typ des Enum eWObinICH. Für diesen speziellen Fall greifen wir auf die FILTERREGELN(ART) zu, und laufen alle Objektgruppen For ii = eFAeinzel.efBLT To eFAeinzel.efMATNR und die dort zuvor definierten Enum-Untermengen (vgl. Abb. 10 und das Filtermodell im Code 2) durch. Für jede Objektgruppe wird dabei eine Prozedur aufgerufen, die die Objekte der Oberfläche ein-/ausblendet, wobei als Parameter beim Aufruf die Informationen
' Aktivierung inkl. Farbformatierung ! Private Sub DoDatumAktiv(ByVal Index As eFAeinzel, _ ByVal AKTIV As Boolean) With FILTER.DATUM(Index) .VON.Enabled = AKTIV .VON.Text = cALLE .BIS.Enabled = AKTIV .BIS = cALLE .VON.BackColor = IIf(.VON.Enabled, eFARBE.eGELB, _ eFARBE.eGRAU) .BIS.BackColor = IIf(.BIS.Enabled, eFARBE.eGELB, _ eFARBE.eGRAU) End With End Sub Private Sub DoStatusAktiv(ByVal Index As eFAeinzel, _ ByVal AKTIV As Boolean) With FILTER.STAT(Index) .Enabled = AKTIV End With End Sub ' Aktivierung inkl. Farbformatierung und zurücksetzen! Private Sub DoArrAktiv(ByVal Index As eFAeinzel, _ ByVal AKTIV As Boolean) With FILTER.ARR(Index) .BZCHN.Enabled = AKTIV .BZCHN.Text = cALLE .NR.Enabled = AKTIV .NR.Text = cALLE .BZCHN.BackColor = IIf(.BZCHN.Enabled, _ eFARBE.eGELB, eFARBE.eGRAU) .NR.BackColor = IIf(.NR.Enabled, _ eFARBE.eGELB, eFARBE.eGRAU) End With End Sub Private Sub DoLandAktiv(ByVal AKTIV As Boolean) With FILTER.LAND .IN.Enabled = AKTIV .AUS.Enabled = AKTIV End With End Sub ' Aktivierung inkl. Farbformatierung! Private Sub DoDataAktiv(ByVal Index As eFAeinzel, _ ByVal AKTIV As Boolean) With FILTER.DATA(Index) .Enabled = AKTIV .Text = cALLE: .BackColor = IIf(.Enabled, _ eFARBE.eGELB, eFARBE.eGRAU): End With End Sub Code 8: Ein-/Ausblendmodule Code 8 listet alle Module auf, die die Aktivierung der Filterobjekte bewirken. Die Prozedur DoDatumAktiv bezieht sich auf die Gruppe der Datumsobjekte, die unter FILTER.DATUM(Index) im Filtermodell gespeichert werden. Der Parameter .DATENART(ii) übergibt einen Boolean-Wert an die Prozedur. Dieser Wert wird über den Parameter AKTIV an die Eigenschaft .Enabled weitergereicht: .VON.Enabled = AKTIV. Ist der Inhalt des Parameters .DATENART(ii) in seinem Wert WAHR - somit auch AKTIV WAHR - so wird die Objektgruppe in der Filtermaske aktiviert, analoges gilt für das Gegenteil. Die Auswahlfelder sollen einen Standardwert anzeigen, dieser wird mittels .VON.Text = cALLE gesetzt, wobei cALLE eine Konstante mit dem Inhalt "Alle" andeutet. Leider werden beim Deaktivieren der Felder nicht die Hintergrundfarben der Auswahlfelder geändert, so dass der Anwender u.U. nicht gleich merkt, ob ihm eine Auswahl zur Verfügung steht oder nicht. Um unnötigen Problemen aus dem Weg zu gehen, bietet es sich an, bei der Deaktivierung eines Auswahlfeldes auch seine Hintergrundfarbe zu ändern. Dies soll die folgende If-Abfrage und Zuweisung bewirken: .VON.BackColor = IIf(.VON.Enabled, eFARBE.eGELB, eFARBE.eGRAU) Demnach wird der Wahrheitswert von .VON.Enabled abgefragt. Ist das Feld sichtbar (=TRUE), behält es seine eFARBE.eGELB. Ist es nicht mehr erreichbar, ist seine eFARBE.eGRAU. Diese Farbwerte wurden zuvor mit dem Eigenschaften-Editor ermittelt und unter einer weiteren benannten Konstanten eFARBE abgelegt. Analoge Betrachtungen gelten für weitere Objektgruppen-Aktivierungsmodule aus Code 8. 5. Nachwort – Szenenwechsel - 3D-Dokumentation "Die Zukunft gehört hier Web-basierten Kataloglösungen, die alle erforderlichen Daten zentral auf einem Rechner speichern. Über Handy und Laptop gelangen diese Daten zu den Servicetechnikern vor Ort. [...] Über dreidimensionale Kataloge können sie 3D-Modelle erstellen, bei denen alle Bauteile klar identifizierbar sind. Mit einem Mausklick wird das Modell herangezoomt, gedreht oder geöffnet, so dass sich die einzelnen Baugruppen auf dem Bildschirm zeigen. Geräte lassen sich realitätsgetreu in sämtliche Bestandteile zerlegen [...].
Durch das Einbinden von Animationen lassen sich Ein- und Ausbaupfade nachverfolgen. [Industrielle Informationstechnik, 6-7 2001, H. Petters, S. 40] 6. Literatur - Anregung
Kritik, Anregungen... Kritik, Anregungen und Kommentare zu diesem Artikel richten Sie bitte direkt an den Autor Peter A. Landau.Kontakt: Peter A. Landau [1] Für die nachfolgenden Ausführungen im Rahmen dieser Dokumentation werden wir das SAP R/3-System gedanklich reduzieren. Abstrahiert betrachtet ist es für uns eine sehr umfangreiche Datenbank mit ausgedehnten Datenanalysemöglichkeiten. [2] Methodisch gesehen verbirgt sich dahinter eine Weiterentwicklung der Datenbanktechnologie - die wir jedoch an dieser Stelle nicht studieren wollen. Aus der logischen Perspektive hingegen betrachtet, handelt es sich hier um ein Datensammlungsobjekt, hier als Datenbank bezeichnet. Für die Analyse, die wir im Rahmen dieser Dokumentation anstellen wollen, sind diese Unterschiede aber unbedeutend. [3] Kein passender Primärschlüssel zum Fremdschlüssel vorhanden. [4] Eine SQL-UPDATE-Anweisung wird wirksam. [5] Prototypisch ist nicht mit unsachkundig gleichzusetzen. Viele Anwendungen aus dem Bereich der Expertensysteme werden auf diese Weise entworfen: "Expertensysteme werden durch fortschreitende Annäherungen an das fertige System erstellt [...]. Dieser Vorgang des Testens und Korrigierens von Entwürfen ist allen Entwicklungen von Expertensystemen gemein und steht im Gegen-satz zu hierarchischen Entwicklungsprozessen, wie dem Top-Down-Entwurf." [Luger, 285] [6] Deaktiviert im Sinne von: Visible = FALSE. [7] Enabled = TRUE, FALSE. Ein-/Ausblenden im Sinne von Visible = TRUE würde den Anwender unnötig verwirren, da er die ihm bekannten Auswahlfelder plötzlich nicht mehr erreicht, sie verschwinden an der Oberfläche der Software. Bei vielen auszublendenden Feldern pro Tabulatorseite entstünde somit der Eindruck der Leere in der Maske und könnte somit als ein undurchdachtes Design missdeutet werden. [8] Frame - Objekte [9] "e" und "f" im efBLT sind aufgrund einer internen Vereinbarung, einer Konvention entstanden. "e" steht für Enum im Datentyp, "f" hingegen bezieht sich auf ein Feld. [10] SSTab [11] Natürlich lassen sich auch mehrere Enums statt Untermengen direkt definieren. [12] Die Anzahl der Array-Elemente im Bild stimmt nicht mit der Anzahl der zu speichernden Elemente überein. Es ist nur ein visuelles Hilfsmittel. [13] Die Wahl des Datentyps soll - wie der gesamte Inhalt der Dokumentation - als Vorschlag und Anregung verstanden werden. Auch die Collection oder eine Klasse, etc. wären denkbar - je nach Absicht, die mit der Modellierung verfolgt wird. [14] Enabled = TRUE, FALSE. Ein-/Ausblenden im Sinne von Visible = TRUE würde den Anwender unnötig verwirren, da er die ihm bekannten Auswahlfelder plötzlich nicht mehr erreicht, sie verschwinden an der Oberfläche der Software. Bei vielen auszublendenden Feldern pro Tabulatorseite entstünde somit der Eindruck der Leere in der Maske und könnte somit als ein undurchdachtes Design missdeutet werden. Dieser Workshop wurde bereits 18.247 mal aufgerufen.
Anzeige
Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv Vol.6 Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
Neu! sevCommand 4.0 Professionelle Schaltflächen im modernen Design! Mit nur wenigen Mausklicks statten auch Sie Ihre Anwendungen ab sofort mit grafischen Schaltflächen im modernen Look & Feel aus (WinXP, Office, Vista oder auch Windows 8), inkl. große Symbolbibliothek. Tipp des Monats Dezemeber 2024 Roland Wutzke MultiSort im ListView-Control Dieses Beispiel zeigt, wie sich verschiedene Sortierfunktionen für ein ListView Control realisieren lassen. TOP Entwickler-Paket TOP-Preis!! Mit der Developer CD erhalten Sie insgesamt 24 Entwickler- komponenten und Windows-DLLs. Die Einzelkomponenten haben einen Gesamtwert von 1605.50 EUR... |
||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |