TurboCalc WorkShop Nr. 2 © 1997 by Günther Klug Frh. v. Biedermann, München Makro-Programmierung_1 Dies ist der erste aus einer ganzen Reihe von (geplanten) Work-Shops zum Thema Makro-Programmierung. Die fast unendliche Anzahl möglicher Makro-Sequenzen ist in nur EINEM Work-Shop nicht zu bewerkstelligen; dazu bedürfte es eines dicken Buches. Da - infolge der (z.Zt.) prekären Lage des Amiga und der (immer schon) fehlenden Risiko-Bereitschaft der Amiga-Presse bzw. der zugehörigen Verlage - ein solches Buch wohl nie erscheinen würde und die Verlage auch lieber Work-Shops (der seichten Art) selbst zusammenbasteln, als entsprechende Angebote von Leuten, die was davon verstehen, zu berücksichtigen, habe ich mich zu dieser Art der Veröffentlichung entschlossen. Falls auf diesen Work-Shop keine mich motivierende Resonanz (neudeutsch "Feedback") erfolgt, wird dies allerdings der Letzte sein, denn ich habe keine Lust, mir für einen elitären Kreis von 5-6 Leuten diese doch recht anstrengende Arbeit zu machen. Das mußte mal gesagt werden dürfen, gel! Bei dieser Gelegenheit möchte ich auch gleich anmerken, daß Work-Shops zum Thema Export von Text und Graphik an andere Programme (PostScript, DTP- und Grapik-Programme und andere Betriebs-Systeme MS-DOS, WINDOWS MAC) von mir NICHT beabsichtigt sind, weil ich mich sonst auch noch mit den Eigenheiten und Fehlern dieser Programme auseinandersetzen müßte! Sie werden hier keine fertigen Anwendungen finden, sondern Makro-Module, welche bei bestimmten Anwendungen immer wieder gebraucht werden. Es mag Ihnen vorkommen, als wäre die Auswahl und Reihenfolge der behandelten Module rein willkürlich - aber dem ist NICHT so! Vielmehr treffe ich die Auswahl entsprechend eigener Erfahrung bezgl. Schwierigkeit und/oder Wichtigkeit für den fehlerfreien Ablauf von Makros. Dieses Mal geht es um die Überprüfung von User-Eingaben unter Verwendung der Funktionen UND (AND), ODER (OR) und XOR. Sie werden in vielen ihrer Applikationen den End-Anwender (der natürlich auch Sie sein können) auffordern müssen, einen Input (also eine Eingabe) zu machen. Dieser Work-Shop befaßt sich mit den diversen Möglichkeiten, solche Eingaben zu überprüfen und notfalls zu korrigieren. SYNTAX DES INPUT-BEFEHLs INPUT(["Text";"Titel";Zelle]) wobei die Definition von zwar optional, aber zur Vermeidung von Fehleingaben aufs DRINGENDSTE zu empfehlen ist. Der User soll wissen, WAS von ihm verlangt wird. Zwar wird - falls SIE keinen erklärenden Text definieren - folgender Default-Text gezeigt... "Bitte Text (für Zellinhalt) eingeben:" ...aber der ist notgedrungen ziemlich nichtssagend. ist die ebenfalls optionale Überschrift, welche im Requester zu sehen sein soll. ist ebenfalls optional und definiert diejenige Zelle, in welche der Input zu tätigen ist. Es zwingt Sie also Niemand, hier eine Zelle zu definieren. Sie sollten aber sicher machen, daß die Eingabe in die richtigen Zelle gemacht wird, denn OHNE Definition einer Zelle wird die Eingabe in die momentan aktuelle Zelle getätigt. Dieses "sicher machen" geschieht alternativ... - weil Sie wissen, daß im Ablauf der Makro-Sequenz die Ziel-Zelle zum Zeitpunkt, da der Input angefordert wird, schon die aktuelle Zelle ist (Probleme tauchen aber möglicherweise dann auf,wenn Sie das Makro ändern und vergessen, daß die dann aktive Zelle evtuell die Falsche ist!). - durch vorheriges Anspringen der Zelle mittels GEHEZU (SELECT) Es gibt natürlich Fälle, in welchen die Zelle, in die ein Input zu tätigen ist, beim Start des Makros noch nicht bekannt ist. Dann müssen Sie andere "Werkzeuge" verwenden, um diese Zelle zu ermitteln: - durch Cursor-Bewegung mittels NACHRECHTS (CURSORRIGHT), NACHLINKS (CURSORLEFT), NACHUNTEN (CURSORDOWN) und NACHOBEN (CURSORUP). - mittels der Makro-Befehle SPALTE (COLUMN) und ZEILE (LINE) bzw. INSPALTE (GOTOCOLUMN und INZEILE (GOTOLINE) - durch vorheriges Anspringen der Zelle mittels AUSWÄHLEN(ZELLEABS) (SELECT(CELLABS)). Wie daraus folgt, ist der einfachste Weg (falls die Zell-Adresse beim Ablauf des Makros IMMER dieselbe ist) die Definition dieses Parameters. Eine Eigenheit von EINGABE (INPUT) sollten Sie auch kennen: Der Input- Requester hat ZWEI Gadgets, die in der Default-Einstellung (also wenn Sie die Option, mittels REQPARA Position und Inhalt der Gadgets selbst zu bestimmen, NICHT wahrnehmen), links "OK" u. rechts "Abbruch" zeigen. Unabhängig davon wird bei Klick auf das linke Gadget (oder RETURN) der Inhalt von überschrieben - auch wenn garkein Input erfolgte UND der Inhalt wird (trotzdem nix drin ist) "textlich" sein! Bei Klick auf das rechte Gadget wird - egal, was Sie (in REQPARA) auch definiert haben - den eventuellen vorhandenen Inhalt von NICHT verändern. Diese Eigenheit zu kennen ist wichtig bei der Abfrage auf den Typ des getätigten Inputs! Soweit also die Handbuch-Lehrstunde. Eingaben sollten IMMER auf Stimmigkeit überprüft werden. Es gibt dafür grundsätzlich 2 Haupt-Kriterien: PLAUSIBILITÄT und/oder EXAKTHEIT In interaktiven Anwendungen ist INPUT einer der Knackpunkte und Quelle von Irritationen, auf die Sie durch clevere Programmierung von Makros prüfend - und notfalls regulierend - einwirken müssen, um den Erfolg einer Anwendung nicht zu gefährden. Die vom Anwender geforderte Eingabe muß in aller Regel ganz bestimmten Kriterien entsprechen, weil davon abhängt, OB - und wenn ja, WIE - das Makro fortgesetzt wird, bzw. ob das End-Ergebnis stimmt. Ob und unter welchen Umständen ein Makro fortzusetzen ist, entscheiden in erster Linie SIE - der Programmierer der Applikation. Sie müssen es wissen, ob eine Fehleingabe... - im Interesse des Gesamt-Erfolges zwingend zum Abbruch führen muß - unter bestimmten Umständen vernachlässigbar oder tolerabel ist - eine Anfrage an den Anwender (ob die eventuell scheinbar falsche Eingabe übernommen werden soll) nötig macht - nach einer vordefinierten Anzahl Fehlversuchen zum Abbruch führt - in eigener Entscheidung (vom Makro) korrigiert werden kann/soll - dem ANWENDER (nach Benachrichtigung) wahlseise Fortsetzung oder Abbruch ermöglichen soll Das (und mehr) ist alles machbar, wenn man nur weiß, WIE! Geforderte Eingaben und darauf angewandte Kriterien können also sein: - wurde überhaupt eine Eingabe (oder nur Return/Abbruch) getätigt? - ist die Eingabe numerisch (mit oder ohne Bereichs-Beschränkung) - ist die Eingabe alphanumerisch (mit/ohne Bereichs-Beschränkung) Beispiel hierfür wäre eine Artikelnummer, welche als Vor- oder Nach-Spann Alphazeichen enthält. - ist die Eingabe reiner Alphatext (mit/ohne Bereichs-Beschränkung) - ist die Eingabe ein Datum (mit/ohne Bereichs-Beschränkung). Der Amiga und TurboCalc haben keine Schwierigkeiten Daten nach dem Jahre 1999 richtig zu erkennen und zu handhaben (im Gegensatz zu Dosen beispielsweise - dies nur nebenbei)! - besteht die Eingabe aus zu vielen oder zu wenigen Zeichen/Ziffern Das Format der Eingabe zu bestimmen ist NICHT Sache des Anwenders, weil der es in den wenigsten Fällen spontan beurteilen kann; SIE müssen es in der Makro-Sequenz gefälligst selbst tun! User-Eingaben sind zu überprüfen, weil - zumindest in professionellen Anwendungen - vermeidbare Fehler UNBEDINGT vermieden werden müssen und unerkannte Fehler katastrophale Folgen haben können! Müssen Eingaben eigentlich immer und unbedingt überprüft werden? Eingaben durch Listenauswahl mit AUSWÄHLENZEIGEN (SELECTTOFRONT) oder Auswahl durch Klick auf Gadgets oder auch die Wahlmöglichkeit, welche mittels REQPARA mit "JA" oder "NEIN" geboten wird, bedürfen wohl keiner Überprüfung; Sie (der Makro-Programmierer) haben es in der Hand, dem Anwender keine falschen Auswahlen anzubieten! Sehr wohl überprüft werden muß jedoch, ob der Anwender ÜBERHAUPT eine Auswahl getroffen hat! Eine Prüfung der Eingabe muß nicht zwingend erfolgen, wenn sie von nachfolgenden Aktivitäten - beispielsweise bei Weiterverwendung als Kriterium innerhalb von Datenbank-Anwendungen - einer Überprüfung standhalten muß, denn... ...wird die Eingabe durch ein SUCHEN mittels Kriterien verifiziert, dann war sie wohl OK - wenn NICHT (also kein zutreffender Datensatz gefunden), muß eine neue Eingabe angefordert, oder zumindest eine Abbruch-Option ermöglicht werden. Bei all dem sollten Sie aber im Hinterkopf behalten, daß selbst der kleinste Arbeits-Schritt Zeit braucht und durch ANFRAGE (REQUEST) bzw. MELDUNG (MESSAGE) erzwungene Unterbrechungen am Gesamt-Ablauf einer Makro-Sequenz oft 95-99.9% ausmachen! Die Ideal-Makro-Sequenz wäre also eine, welche KEINERLEI Unterbrechung benötigt - aber wann erreicht man je das Ideal!? Bezogen auf INPUT muß man also abwägen, ob die Vorprüfung des Input Zeit einspart, OBWOHL durch SUCHEN im Datenbank-Teil der Input ein zweites Mal "geprüft" wird. Die Antwort darauf wird in der Regel JA sein, weil die Vorprüfung in Prozessorgeschwindigkeit erfolgt und bei richtiger Eingabe die Chance, daß auch der Datenbank-Teil keine Fehler meldet, enorm verbessert wird. Plausibilitätsprüfung --------------------- Wenn Sie den Anwender bitten, einen Namen einzugeben, bleiben Ihnen nur wenige Möglichkeiten der Überprüfung. Allerdings können Sie wohl ausschließen, daß eine numerische oder alphanumerische Eingabe korrekt ist und auch ein Name mit weniger als 3 Buchstaben dürfte wohl zu den Fehler-Aspiranten zählen (außer im Science Fiction Bereich). Solche Eingaben können Sie stillschweigend akzeptieren, oder mitttels ANFRAGE auftretende Zweifel ausräumen. Hellhörig sollte Ihre Applikation aber zumindest dann werden, wenn der Anwender ein Geburtsdatum eingibt, welches ein Alter von 123 Jahren bescheinigt (außer bei historischen Persönlichkeiten oder sündteueren Weinen und Cognacs). Dasselbe gilt, wenn das eingegebene Gesamt-Gewicht der Zutaten einer Rezeptur (Bäckerei-Anwendung) das Fassungsvermögen der Knetmaschine übersteigt, oder das Verhältnis Wasser/Mehl in einer Brot-Rezeptur als Endprodukt eine Mehlsuppe ergeben würde. Dies sind nur 3 Beispiele aus einer Legion denkbarer Kriterien! Exaktheitsprüfung ----------------- Hier ist - entsprechend der Anwendung - die Erwartung der Maßstab. Die Eingabe muß also entweder GENAU einem Vergleich standhalten und/oder einem ganz bestimmten Format (z.B. Datum) entsprechen oder zumindest innerhalb eines umrissenen Bereiches sein, um vom Makro akzeptiert zu werden; dies betrifft in der Regel NUMERISCHE Eingaben. WELCHE MÖGLICHKEITEN DER ÜBERPRÜFUNG GIBT ES? Jedenfalls mehr, als Sie glauben - wetten? Direkte Prüfung: - ist die Zelle, in welche die Eingabe gemacht wurde, leer, Fließkomma-Zahl, Ganzzahl, Datum, Zeit, Boolean, Text Beispiel_1 (siehe dazu Tabelle "WS_Makros_1.TCD"): Eine imaginäre Kunden-Datenbank soll erweitert werden. Irgendwann muß der Anwender also einen Namen eingeben. WO dies geschieht, bestimmen SIE - der Programmierer der Anwendung durch geschickte Nutzung der dafür geeigneten Makros und Funktionen (dafür ist demnächst ein eigener Work-Shop vorgesehen). Hier ist es immer die Zelle A5 . Gleich zu Beginn eines Makros sollten Sie dem Anwender die Möglichkeit einräumen, das Makro abzubrechen - er hat vielleicht das falsche Makro aufgerufen! Tun Sie es NICHT, kann der Anwender in eine Lage kommen, wo er sich nicht mehr zu helfen weiß! Das Makro beginnt in Zelle B1 und hat den Namen: =MACRO("DB_modify1") ;der definierte Name des Makro =ANFRAGE("Datenbank modifizieren?¶ Wenn NEIN, klicken Sie auf Abbruch!") =IFGOTO(B2;B5) ;wenn OK, geht das Makro bei B5 weiter =GOTO(B28) ;wenn Abbruch endet das Makro bei B28 =SELECT(A5) ;der Zell-Cusor springt in Zelle A5 =INPUT("Bitte den Namen eingeben.";"Datenbank modifizieren") Was ist bisher passiert? 1. Das Makro "DB_modify1" wurde gestartet 2. Der Anwender kann weitermachen (Klick auf OK) oder abbrechen (Klick auf Abbruch) 3. Wenn OK, weiter in B5 3. Wenn Abbruch fährt das Makro in B28 fort, wo dem Anwender mitgeteilt wird, daß ER das Makro abgebrochen hat und das Makro endet in B29 4. Da der Anwender nicht weiß, wohin ein neuer Datensatz geschrieben werden soll und auch nicht, wohin in diesem Datensatz der Name des Kunden gehört, übernimmt das Makro die Suche nach dem richtigen Ort. In diesem Beispiel ist es die Zelle A5. 5. Nun wird der Anwender im erscheinenden Requester höflich zur Eingabe des Namens aufgefordert. Der Text "Datenbank modifizieren" erscheint in der Titelzeile des Requesters. Der 3. Parameter, der die Zelle, in die der Input erfolgen soll bezeichnet, ist hier unnötig, weil der Cursor bereits in der aktiven Zelle ist! ACHTUNG! Einer der vielen Vorzüge von TurboCalc ist der, daß bei Erscheinen eines Requesters NICHT alle anderen Aktivitäten gesperrt sind! Sie könn(t)en also dennoch z.B ein anderes auf dem Screen befindliches Blatt oder eine AmigaGuide-Hilfe Datei in den Vordergrund holen, um was nachzulesen oder das Display beliebig verschieben usw. ABER - wie das mit der Freiheit so ist - es bestehen durchaus auch Gefahren: Hüten Sie sich SEHR durch Herumgeklicke die Position des Cursors (also die aktive Zell-Adresse) zu verändern! Die Folgen wären unvorhersehbar - na, eigentlich schon; es gäbe eine versaute Tabelle! Wie weiter oben beschrieben, haben Sie nicht viele Möglichkeiten, eine Namen-Eingabe zu überprüfen; also prüfen wir... a) wurde überhaupt was eingegeben b) wurde "Text" eingegeben c) ist der Text wenigstens 3 Zeichen lang Jetzt wirds interessant: Der Anfänger wird in "konventioneller" Weise die DREI Prüfungen (und zu Jeder die eventuelle Rückfrage beim Anwender mit Neu-Eingabe und erneuter Prüfung und Rückfrage usw.) durchziehen... ...und hat damit die Möglichkeit, dem Anwender zu sagen, WELCHEN Fehler er bei der Eingabe gemacht hat! Ist das beabsichtigt, dann käme aber noch eine genauere andere Methode in Frage! Ziel dieses WS ist es, Ihnen die für die Anwendung OPTIMALE Lösung von Problemen, NICHT unbedingt die SCHNELLSTE nahezubringen. Welche für Ihre Anwendung die optimale ist, müssen Sie aber selbst entscheiden. Zunächst fahren wir fort mit der "konventionellen" Variante: =IFGOTO(NOT(ISTLEER(CELL(0;0)));B13) =REQPARA(;;"Nochmal";"Abbruch") =ANFRAGE("Sie haben nix eingegeben!¶Nochmal oder Abbruch?") =IFGOTO(NOT(B9);B27) =CLEAR(0) =GOTO(B6) =IFGOTO(ISTTEXT(CELL(0;0));B19) =REQPARA(;;"nochmal";"Abbruch") =ANFRAGE("Sie haben keinen Text eingegeben...") =IFGOTO(NOT(B15);B27) =CLEAR(0) =GOTO(B7) =IFGOTO(LÄNGE(CELL(0;0)>=3);B25) =REQPARA(;;"nochmal";"Abbruch") =ANFRAGE("Sie haben weniger als 3 Zeichen eingegeben...") =IFGOTO(NOT(B21);B27) =CLEAR(0) =GOTO(B6) =MESSAGE("Ihre Eingabe war OK") =GOTO(B29) =CLEAR(0) =MESSAGE("Das Makro wurde vom Anwender abgebrochen!") =RETURN Was ist da passiert? 6. War die Zelle NICHT leer (der Anwender hat irgendwas eingegeben), gehts bei B13 weiter 7. Andernfalls wird dem Anwender unter die Nase gehalten, daß er keine Eingabe gemacht hat und er kann wählen, ob er es nochmal versuchen oder abbrechen will. 8. Wählt er "nochmal" wird zuerst seine falsche Eingabe gelöscht und dann gehts zurück zu B6 (INPUT); da die aktive Zelle immer noch A5 ist, braucht nicht nach B5 zu "=SELECT(A5)" gesprungen zu werden! Wählt er Abbruch, gehts weiter bei B27, wo ein eventueller Inhalt in Zelle A5 gelöscht wird und ihm dann (in B28) mitgeteilt wird, daß ER das Makro abgebrochen hat. Das Makro endet in B29 mit "=RETURN". 9. War A5 NICHT leer, geht es in B13 weiter mit der Prüfung, ob die Eingabe TEXT war - usw. usw., bis alle 3 Prüfungen durch sind. Nun die schnelle Variante: Weil nicht nur eingesparte Unterbrechungen durch unnötige Anfragen, sondern auch eingesparte Makro-Befehle den Makro-Ablauf verkürzen, sollten Rechenschritte möglichst zusammengefaßt werden. Dazu sind die boolschen Funktionen UND (AND), ODER (OR) und XOR gut geeignet. Überlegen wir: ZWEI Kriterien müssen erfüllt werden, damit wir (ausreichend) sicher sein können, daß die Eingabe korrekt war: Sie muß vom Typ Text sein und der muß mehr als 3 Zeichen enthalten SYNTAX DER Funktion UND (AND): UND(Wert1;Wert2;Wert3;...) wobei die mindestens ZWEI Parameter Zahlen oder Wahrheitswerte (bzw. Aussagen, welche mit WAHR oder FALSCH beantwortet werden können) sein müssen. Der Rückgabe-Wert der Funktion ist WAHR, wenn ALLE Werte (Parameter) WAHR sind und FALSCH, wenn auch nur ein Wert FALSCH ist. Dies wären also die 2 hier zu machenden Aussagen (Behauptungen): =ISTTEXT(CELL(0;0)) =LÄNGE(CELL(0;0))>=3 Die erste "behauptet", daß die Zelle textlich ist. Wenn dies zutrifft, wird WAHR zurückgegeben, andernfalls FALSCH und die andere, daß die Länge des Inhaltes >=3 ist. Wenn es zutrifft, wird WAHR zurückgegeben, andernfalls FALSCH Fassen wir diese 2 Aussagen mittels UND zu EINER Aussage zusammen, nämlich daß BEIDE Aussagen WAHR ergeben, dann sieht das so aus: =AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3) Nun wird WAHR zurückgegeben, wenn BEIDE WAHR sind und FALSCH wenn unsere Behauptung (daß BEIDE WAHR sind) NICHT zutrifft, sondern nur eine WAHR ist oder beide FALSCH sind. Soweit also die Handbuch-Lehrstunde zu AND. Alles, was wir nun noch zu tun haben ist, mittels SPRINGEWENN (IFGOTO) zu bestimmen, WO das Makro für den einen und anderen Fall fortgeführt werden soll. SYNTAX DES Befehls SPRINGEWENN (IFGOTO) : IFGOTO(Bedingung;Zelle) Wenn WAHR zurückgibt, wird zu gesprungen, ansonsten wird in der nächsten Zeile fortgefahren. Dies gibt uns eine zusätzliche Steuerungsmöglichkeit an die Hand, indem wir durch geschickte Formulierung von auch dafür sorgen können, daß die Bedingung FALSCH als Erwartungs-Wert zurückgibt - dazu später mehr. Es ist also ganz leicht: Man schreibe in die betreffende Zelle =IFGOTO(Bedingung;B47) und ersetze "Bedingung" durch die oben erarbeitete Zeile =AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3) jedoch ohne das "=" - was ergibt... =IFGOTO(AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3);B47) Hier (siehe Makro "DB_modify2") wird zunächst darauf verzichtet, dem Eingeber den genauen Fehler zu nennen, sondern ihm lapidar mitgeteilt, daß "etwas" falsch war. =MACRO("DB_modify2") =ANFRAGE("Datenbank modifizieren?¶ Wenn NEIN, klicken Sie auf Abbruch!") =IFGOTO(B36;B39) =GOTO(B50) =SELECT($A$5) =INPUT("Bitte den Namen eingeben.";"Datenbank modifizieren") =IFGOTO(AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3);B47) =REQPARA(;;"nochmal";"Abbruch") =ANFRAGE("Eingabe war nicht OK") =IFGOTO(NOT(B43);B49) =CLEAR(0) =GOTO(B40) =MESSAGE("Ihre Eingabe war OK") =GOTO(B51) =CLEAR(0) =MESSAGE("Das Makro wurde vom Anwender abgebrochen!") =RETURN Wie Sie unschwer sehen, ist das Makro statt 29 (beim Makro DB_modify1) nur 17 Zeilen lang und es enthält nur EINE einzige Prüfung. Auffallend ist hier aber ein "Manko", welches in der "langen" Variante nicht zu beklagen war: Es wird dem Anwender nicht mitgeteilt, WAS er (evtl.) falsch machte! Nun, dem kann gesteuert werden. Wir ZEIGEN ihm seinen Input und so kann er selbst sehen, was nicht stimmte! Diverse Befehle ermöglichen es, dem Anwender im erscheinenden Requester einen Zell-Inhalt als Text zu zeigen; dazu gehören ANFRAGE und MELDUNG. Weil aber MELDUNG (MESSAGE) hier fehl am Platz wäre, weil es in seinem Requester keine Wahlmöglichkeit bietet, bleiben wir bei ANFRAGE und tauschen den Befehl in Zelle B43 durch diesen aus: =ANFRAGE("Ihre Eingabe: "+TEXT(CELL(0;0))+" war nicht OK") das ergibt - falls z.B. "123" eingegeben wurde - im Requester den Text Ihre Eingabe: 123 war nicht OK Weil wir aber dem Anwender das recht deutlich machen wollen, verwenden wir ein paar Tricks, um das zu bewerkstelligen: Mit "¶" (was mit ALT-P zu erzeugen ist) kann man einen Zeilenvorschub erzwingen und ergänzt durch ein paar Leerzeichen sieht der Befehl dann so aus: =ANFRAGE("Ihre Eingabe:¶ --> "+TEXT(CELL(0;0))+"¶war nicht OK") Nun sieht der Anwender überdeutlich, was er angerichtet hat: Ihre Eingabe: --> 123 war nicht OK Weiter oben war die Rede von einer "zusätzlichen Steuerungsmöglichkeit" durch geschickte Formulierung von bei IFGOTO. Nun, die ganze "Geschicklichkeit" besteht in der Umkehrung der Bedingung - wir setzen einfach ein "NOT" an den Anfang der Bedingung - was bei einer (erwarteten) richtigen Eingabe den Retourn-Wert FALSCH erzwingt - und ändern den Bezug (hier "B47" in "B69") und damit natürlich auch die Folgen für den Fall, daß die Eingabe NICHT richtig war. Wozu diesen Umstand?? Hat doch so auch ganz gut geklappt!? Stellen Sie sich vor, Sie hätten MEHRERE Datenbanken und bei allen muß eine (ähnliche) Abfrage gemacht werden; dann können Sie beispielsweise bei allen Datenbanken mittels ROUTINE (CALL)... - die Abfragen auslagern und im Makro nur das Sub-Makro aufrufen, das die Abfragen abarbeitet und/oder - wie im nachfolgenden Beispiel (Makro "DB_modify3") dem Anwender eine bestimmte Anzahl von Fehleingaben zugestehen und ggfls. das Makro zwangsweise beenden. ...und sparen sich u.a. EINIGES an Programmier-Arbeit! Dazu müssen allerdings ein paar Dinge umgestellt und/oder modifiziert und ein paar neu programmiert werden: =MACRO("DB_modify3") =PUT(0;B87) =REQUEST("Datenbank modifizieren?¶ Wenn NEIN, klicken Sie auf Abbruch!") =IFGOTO(B62;B65) =GOTO(B75) =SELECT($A$5) =INPUT("Bitte den Namen eingeben.";"Datenbank modifizieren") =IFGOTO(NOT(AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3));B69) =GOTO(B73) =CALL(B89) =IFGOTO(NOT(B87=2);B66) =LÖSCHEN(3) =GOTO(B77) =MESSAGE("Ihre Eingabe war OK") =GOTO(B77) =CLEAR(3) =MESSAGE("Das Makro wurde vom Anwender abgebrochen!") =RETURN Zusätzlich wird ein "Fehlerzählwerk" in B87 installiert und ein (nicht mit Namen definiertes) Sub-Makro "Fehlerbehandlung" ab Zelle B89 neu erstellt. Fehlerzählwerk 0 Sub-Makro Fehlerbehandlung =PUT(B87+1;B87) =IFGOTO(B87>1;B97) =REQPARA(;;"nochmal";"Abbruch") =ANFRAGE(" Ihre Eingabe war nicht OK¶EINE Chance haben Sie noch!") =IFGOTO(B93;B100) =PUT(2;B87) =GOTO(B99) =MELDUNG("Sie haben 2 Mal falsch eingegeben!¶ Makro wird abgebrochen!") =GOTO(B100) =MESSAGE("Das Makro wurde vom Anwender abgebrochen!") =RETURN Was ist hier anders? 1. Wird das Fehlerzählwerk in B87 auf 0 gestellt. 2. Durch das vorangestellte "NOT" wurde erreicht, daß im Falle einer Falscheingabe nicht in der NÄCHSTEN Zeile fortgefahren wird, sondern in Zelle B69, wo mit CALL zum Sub-Makro verzweigt wird (welches die Fehlerbehandlung durchzieht). =IFGOTO(NOT(AND(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3));B69) Da IFGOTO nur eine Zell-Adresse als Ziel erlaubt (also den Befehl CALL beispielsweise nicht), kann CALL nur über diesen kleinen Umweg (hier B69) aufgerufen werden. 3. Wenn die Eingabe OK war, gehts NUN also in der NÄCHSTEN Zeile (B68) und dem dort stehenden Befehl "GOTO(B73)" weiter, wo dem Anwender bestätigt wird, daß er ein braves Kind war - und das Makro endet. 4. Bei einer Falscheingabe wird NUN also zu B69 gesprungen, wo mit dem Befehl "=CALL(B89)" zum Sub-Makro "Fehlerbehandlung" verzweigt wird. Hier wird - zunächst das Fehlerzählwerk um 1 erhöht - geprüft ob das Fehlerzählwerk nun >1 ist und in diesem Falle zu B97 verzweigt, wo dem Anwender mitgeteilt wird, daß das Maß voll ist und das Makro wegen 2-maliger Fehleingabe endet. - War es aber die ERSTE Fehleingabe, wird ihm die Wahl gelassen, es nochmal zu versuchen oder seinerseits abzubrechen. Entscheidet er sich für "Abbruch", wird Zählwerk auf 2 gestellt und die Meldung "Abbruch durch Anwender" gezeigt. Entscheidet er sich für "nochmal" wird das Sub-Makro beendet. 5. Nun gehts zurück zum Haupt-Makro, wo in B70 geprüft wird, ob das Fehlerzählwerk NICHT 2 ist und in diesem Fall ein weiterer Versuch in B66 (INPUT) gestartet. Andernfalls wird die falsche Eingabe gelöscht und das Makro beendet. Soweit wäre der Work-Shop schon erledigt - aber da fehlen doch noch die anderen boolschen Funktionen OR und XOR ! Nochmal eine Handbuch-Lehrstunde: SYNTAX DER Funktion ODER (OR): ODER(Wert1;Wert2;Wert3;...) wobei die mindestens ZWEI Parameter Zahlen oder Wahrheitswerte (bzw. Aussagen, welche mit WAHR oder FALSCH beantwortet werden können) sein müssen. Der Rückgabe-Wert der Funktion ist FALSCH, wenn ALLE Werte (Parameter) FALSCH sind und WAHR, wenn auch nur ein Wert WAHR ist. ODER macht also genau das Gegenteil von UND Wenn wir also bei unserem Beispiel bleiben, müssen wir feststellen, daß wir mit ODER nicht zum Ziel kommen, denn wenn die BEIDEN Bedingungen =ISTTEXT(CELL(0;0)) =LÄNGE(CELL(0;0))>=3 - FALSCH sind, wird zwar WAHR zurückgegeben und wir wissen, daß die Eingabe tatsächlich falsch war und - wenn nur EINE davon WAHR ist, wird FALSCH zurückgegeben, womit wir wieder wissen, daß die Eingabe falsch war aber wir werden mit dieser Formel: =OR(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))>=3) nie sicher wissen, ob die Eingabe RICHTIG war! Aber damit ich Ihnen wenigstens EINE (zugegeben doch etwas abstruse) Möglichkeit demonstriere, auch mit ODER (OR) zum Ziel zu kommen, diese Formel: =OR(ISTTEXT(CELL(0;0))ANDLÄNGE(CELL(0;0))>=3;ISTTEXT(CELL(0;0))ANDLÄNGE(CELL(0;0))>=3) Der Trick dabei ist, daß der Funktion ODER zwei GLEICHLAUTENDE Parameter verpaßt werden; BEIDE enthalten je ZWEI Aussagen, welche nur dann WAHR sind, wenn die Eingabe SOWOHL Text ist, ALS AUCH länger als 2 Zeichen. Damit ODER eine solche Konstruktion akzeptiert, wurde ein weiterer Trick angewandt: Jede der beiden Aussagen wurde mit UND (AND) zu jeweils EINER Aussage verknüpft und sieht so aus: ISTTEXT(CELL(0;0))ANDLÄNGE(CELL(0;0))>=3 Damit wird sichergestellt, daß ODER auf jeden Fall "FALSCH" zurückgeben muß, wenn BEIDE Aussagen NICHT zutreffen und WAHR nur dann, wenn eine der beiden zutrifft; da aber beide gleich sind...? ecco! Es gibt zwar in der Tabelle keine eigene Makro-Sequenz dafür, aber wenn Sie die Konstruktion ausprobieren wollen, dann kopieren Sie den Inhalt der Zelle B56 einfach nach B47 und starten Sie das Makro "DB_modify2". Wie gesagt, das ist "über mehrere Ecken" und sollte zur Demonstration (was alles machbar ist) dienen, aber sollten Sie irgendwann tatsächlich eine gute Verwendung dafür finden - lassen Sie es mich wissen (mir fällt momentan nix dazu ein)! Kommen wir lieber zur Funktion XOR (steht für "eXklusiv OdeR"): SYNTAX DER Funktion XOR: XOR(Wert1;Wert2;Wert3;...) Die Funktion XOR gibt FALSCH zurück, falls eine GERADE Anzahl der Werte (Parameter) WAHR oder NICHT-NULL sind. Das paßt doch hier! Wir brauchen unsere bekannten ZWEI Aussagen, welche WAHR sein müssen, damit XOR "FALSCH" zurückgibt, also =XOR(ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))=>3) !?? Der User gibt "Heini" ein und XOR gibt prompt zurück, was wir erwartet haben, nämlich FALSCH - weil beide Aussagen WAHR sind. Leider gibt es da noch den Passus "oder NICHT-NULL" ! Wenn der Anwender also eine Zahl eingibt, dann ist - "ISTTEXT" zwar FALSCH aber NICHT-NULL und - "LÄNGE" ergibt bei Zahlen den Fehler #TYP also auch NICHT-NULL folglich wird XOR wieder FALSCH zurückgeben - weil eine gerade Anzahl der Werte NICHT-NULL ist - und das wäre für unseren Zweck fatal! Klingt kompliziert, gel? Wir müssen dafür sorge tragen, daß der XOR-Rückgabe-Wert zweifelsfrei interpretiert werden kann, wobei es ganz egal ist, WIE er lautet! XOR darf also nur dann FALSCH zurückgeben können, wenn tatsächlich NUR die (hier 2) von uns gewünschten Aussagen WAHR sind und andere mögliche Eingaben (Zahl, Leer, Datum, Formel) nicht zu einer GERADEN Anzahl von WAHR-Werten führen können. Da haben wir glücklicherweise keine Probleme, denn diese "anderen" möglichen Eingaben schließen einander aus (können nicht gleichzeitig existieren), womit eine einfache Aufzählung genügt. Die Ausnahme davon ist Text. Wie wir weiter oben gesehen haben, kann eine Zelle zugleich Text sein und doch leer (RETURN oder OK bei Input, ohne eine Eingabe)! Diese Möglichkeit wird aber bereits unterbunden durch die 2. Bedingung, daß LÄNGE mindestens 3 sein muß! Die nachfolgende Konstruktion deckt praktisch all das ab. Sollten Sie "Formel" hier vermissen, dann bedenken Sie, daß eine Formel berechnet wird und somit irgendwas ergibt! Auch ein Abbruch bei INPUT kann uns nicht schrecken, denn dann wird ja der alte Inhalt erhalten bleiben und der kann nix anderes sein, als was der Anwender auch eingegeben haben könnte! =XOR(ISTDATUM(CELL(0;0));ISTZAHL(CELL(0;0));ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))=>3) Dies muß nun in "IFGOTO(Bedingung;Zelle) integriert werden zu =IFGOTO(XOR(ISTDATUM(CELL(0;0));ISTZAHL(CELL(0;0));ISTTEXT(CELL(0;0));LÄNGE(CELL(0;0))=>3)=FALSCH;A122) und wie es funktioniert, können Sie testen, wenn Sie "DB_modify4" in der Tabelle starten. Natürlich ist diese Konstruktion für den hier erforderlichen Zweck maßlos "over-dressed", aber es sind möglicherweise eine ganze Reihe von Anwendungen denkbar, wo man zu solch einem Konstrukt greifen muß (nur mir fällt wieder nix ein)! ACHTUNG! IFGOTO reagiert auf den WAHR-Wert, aber XOR gibt (im Gegensatz zu den anderen Beispielen mit UND oder ODER der Tabelle) FALSCH zurück, wenn unsere beiden Bedingungen zutreffen! Deshalb endet obige Befehlszeile mit "=FALSCH;B122)" ! Zum Abschluß dieses Work-Shop noch so ein "overdressing": =IFGOTO(XOR(OR(ISTZAHL(CELL(0;0));ISTLEER(CELL(0;0));ISTDATUM(CELL(0;0)));OR(NOT(ISTTEXT(CELL(0;0)));ISTLEER(CELL(0;0)));LÄNGE(CELL(0;0))>=3);$B$122) Was ist das denn? =IFGOTOBedingung;$B$122) das dürfte klar sein! wobei ist... XOR(Wert1;Wert2) Xor hat hier zwar scheinbar nur ZWEI Werte; und da beide WAHR sein müssen, damit XOR den (erwünschten) Return-Wert FALSCH liefert, kann das schon verwirren... ABER wer sagt denn, daß man bei XOR nicht auch mit einem Return-Wert WAHR das gewünschte Ergebnis erreichen kann? besteht aus.. OR(ISTZAHL(CELL(0;0));ISTLEER(CELL(0;0));ISTDATUM(CELL(0;0))) besteht aus... OR(NOT(ISTTEXT(CELL(0;0)));ISTLEER(CELL(0;0)));LÄNGE(CELL(0;0))>=3) ...die Werte 1 & 2 sind ODER-Verknüpfungen mit ihrerseits je 3 Werten und die liefern (wie weiter oben unter "Syntax der Funktion ODER" bereits beschrieben) FALSCH, wenn ALLE Werte (Parameter) FALSCH sind und WAHR, wenn auch nur ein Wert WAHR ist. Somit kann XOR unter dieser Bedingung entweder WAHR;WAHR oder WAHR;FALSCH oder FALSCH;FALSCH empfangen. Hat der Anwender "Heini" eingegeben, wird FALSCH ergeben, weil der Input weder Zahl, noch Leer, noch Datum ist und wird WAHR sein, weil der Input zwar weder NICHT-Text, noch LEER ist aber die Länge >=3 hat. Folglich wird XOR den Wert WAHR zurückgeben (den wir ja bei der Art der Konstruktion erwarten!). Anders als beim vorigen Beispiel (wo XOR FALSCH zurück gab) darf HIER am Ende der Makrozeile das "=FALSCH;" NICHT angehängt werden, weil sonst in die falsche Zelle gesprungen wird (wenn Sie diese Alternative in das Makro "DB_modify4" einbauen !!! In welcher Anwendung so ein Monstrum von Nutzen sein kann, hab ich nicht ausgetestet - das überlasse ich Ihnen ;-)) oder bringe es in einem weiteren Work-Shop (irgendwann). Jedenfalls endet DIESER jetzt, denn 840 Zeilen sind genug. Viel Spaß!