Home - Über mich - Bugastadt 2001 - Ausflüge & Reisen - Texte - Alles Kino - Theater & Kabarett - Gabi gucken - Credits |
Foto: Uwe Pirr Informatik |
Programmieren in HyperTalk, Teil III
Dabei sind fast alle Grafikbefehle in HyperTalk nach dem gleichen Schema aufgebaut. Zuerst wird mit choose <Werkzeug> eines der Werkzeuge aus der Palette aufgerufen und dann wird mit drag <alte Position> to <neue Position> das Bewegen mit gedrückter Maustaste simuliert. Um z.B. ein Rechteck zu zeichnen, sind in HyperTalk nur folgende beiden Befehle nötig:
choose rectangle tool drag from 30, 30 to 130, 130Damit haben wir ein 100 x 100 Pixel großes Quadrat auf unsere Karte gezeichnet. Wie die Werkzeuge alle heißen, ist aus folgender Abbildung ersichtlich:
Abb. 1: Die Werkzeugpalette
Abb. 2: Die Füllmusterpalette
set pattern to 37wird z.B. jede nachfolgende füllbare Fläche mit dem Flechtmuster ausgefüllt. Wenn sie nun von HyperTalk aus mit vielen möglichen Mustern und Attributen herumgespielt haben, möchten Sie vielleicht irgendwann einmal wieder alles auf den ursprünglichen Wert (Default) setzen. Natürlich können Sie das, in dem Sie mit "set" jedes einzelne Muster und jedes einzelne Attribut auf den Defaultwert setzen. Aber erstens: Wissen Sie alle Defaultwerte? Und zweitens: Haben Sie den Überblick, welche Attribute und Muster sie verändert haben? HyperTalk bietet hier eine einfachere Alternative mit
reset paintwerden alle Malattribute wieder auf die ursprünglichen Werte zurückgesetzt. Und wenn Sie dann nicht vergessen, auch wieder das "Browse Tool", also den Zeigefinger-Cursor auszuwählen (mit choose browse tool), dann kann der Anwender Ihres Programms anschließend auch wieder Knöpfe anklicken, Menüs auswählen oder in Feldern Eintragungen vornehmen. KoordinatensystemeWir haben bei obigem drag-Befehl gesehen, daß wir von irgendwelchen (x,y)-Koordinaten zu irgendwelchen anderen (x,y)-Koordinaten die Maus ziehen. HyperCard hat nun, wie fast alle Computer-Koordinatensysteme, den 0-Punkt (0, 0) in der linken oberen Ecke. Die x-Koordinaten steigen von links nach rechts, die y-Koordinaten von oben nach unten. So ist das größte Koordinatenpaar (xMax, yMax) in der rechten unteren Ecke der Karte zu finden. Und die Maßeinheit ist Pixel. So hat das klassische HyperCard-Fenster die Ausmaße von 512 x 342 Pixeln (das sind die Ausmaße des 9"-SE-Monitors). In der rechten unteren Ecke haben wir daher dort das Koordinatenpaar (512, 342), in der linken oberen Ecke das Koordinatenpaar (0, 0).Nun sind aber in der "realen" Welt die Koordinatensysteme in der Regel anders ausgerichtet: Das kleinste Koordinatenpaar (xWmin, yWmin) ist links unten, das größte (xWmax, yWMax) ist rechts oben zu finden. Und (xWmin, xWmax) müssen nicht (0, 0) betragen, sondern können beliebige negative oder positive Werte annehmen. Und außerdem wird in der Regel in der realen Welt nicht in Pixeln, sondern in Metern, Zentimetern, Inches oder irgend etwas anderem gemessen. Zum vierten wollen wir in der Regel nicht die gesamte reale Welt auf der HyperCard-Karte abbilden, sondern nur einen Ausschnitt daraus. Dieser Ausschnitt wird in der Literatur oft Window genannt, leider genauso wie die Fenster auf dem Apple-Desktop. Also bitte nicht verwechseln. Fünftens habe ich, um die gesamte Angelegenheit möglichst allgemein zu halten, auch nicht das gesamte HyperCard-Fenster als Zielausschnitt gewählt, sondern ebenfalls nur einen 300 x 300 Pixel großen Ausschnitt daraus. Dieser Ausschnitt wird in der Literatur Viewport genannt. Wir müssen also eine Koordinatentransformation vornehmen, eine Window-Viewport-Transformation. (Wegen der oben angesprochenen Verwechslungsgefahr bevorzuge ich die anderen in der Literatur verwendeten Begriffspaare Weltkoordinaten (WC) und Devicekoordinaten (DC). Also lassen Sie uns in Zukunft immer von einer WC -> DC-Transformation sprechen, um Verwechslungen auszuschließen. Keine Angst, dies hört sich schlimmer an, als es ist und es sind auch nur einige wenige elementare Rechnungen notwendig.
Abb. 3: WC nach DC Koordinaten
Dann betrachten wir auch in unserem HyperCard Fenster ein Rechteck, festgelegt durch die Koordinatenpaare (xMin, yMin) und (xMax, yMax). Dieses Rechteck kann das gesamte Fenster (oder den gesamten Bildschirm) ausfüllen, muß es aber nicht. Innerhalb dieses Rechteckes sollen alle unsere Bildpunkte (x, y) liegen, die den Weltpunkten (xW, yW) innerhalb unseres Ausschnittes aus den Weltkoordinaten entsprechen. Mit Hilfe obiger Zeichnung erhalten wir leicht folgende Transformationsformeln:
Abb. 4: WC nach DC Koordinaten mit dem DC-Urpsrung links oben
Business ChartsCharts gehören zu den am meisten gewünschten Computeranwendungen. Ob in einer Studienarbeit die Ergebnisse optisch aufbereitet werden sollen oder ob ein Geschäftsbericht den Gesellschaftern vorgelegt wird. Kaum jemand kommt ohne diese Grafiken aus. Ich habe oft den Eindruck, daß Tabllenkalkulationen wie Excel nicht wegen ihrer rechnerischen Fähigkeiten so populär geworden sind, sondern weil sie so schöne Business Charts erstellen. (Wie ein ehemaliger Chef von mir behauptete, sei dies dem KVI-Prinzip geschuldet: Kinder, Vorstände und Idioten bräuchten nun einmal viele bunte Bilder.) Wir werden daher als Beispielanwendung für die Graphikprogrammierung in HyperTalk solch ein Business Chart Werkzeug schreiben.Wir legen als erstes einen neuen Stack an und schreiben ein Background Script (siehe Listing 1). In diesem Script erkennen Sie leicht obige Formeln wieder, nur xMin und yMin heißen hier xOffset und yOffset. Sie sind mit Werten versehen, die eine 300 x 300 Pixel große Zeichenfläche links in das HyperCard-Fenster einpassen. Falls Sie mit einer anderen Kartengröße arbeiten wollen, müssen sie diese Werte und gegebenenfalls auch xMax und yMax ändern. Diese Konstanten sind durch Funktionen realisiert, damit sie auf keinen Fall versehentlich andere Werte zugewiesen bekommen. Das Handle initGraph löscht die gesamte Zeichenfläche, falls Sie dieses nicht wollen (weil z.B. links noch eine Zeichnung ist, die nicht gelöscht werden soll), müssen Sie ebenfalls die Koordinaten entsprechend ändern. Das Handle closeGraph sorgt dafür, daß alles wieder zurückgesetzt wird und gibt uns die Sicherheit, daß wir nichts unaufgeräumt im Stack zurücklassen. Daher sollte er nach erfolgter Zeichnung unbedingt aufgerufen werden. Auf die verschiedenen Achsenkreuze komme ich später bei den einzelnen Charts zurück, wo sie aufgerufen werden. Scale übernimmt die Skalierungsfunktionen, wenn Sie aber wollen, daß bei Ihrer Zeichnung die Originalproportionen erhalten bleiben sollen, sollten Sie stattdessen unConstrained benutzen. (Diese Prozedur wird in unserem Beispielstack nicht aufgerufen.) Dieses Handle berechnet das Minimum von xFactor und yFactor und rechnet mit diesem als gemeinsamen Faktor für beide Koordinatenrichtungen. Das ist dann wichtig, wenn z.B. ein Kreis ein Kreis bleiben und nicht zur Ellipse deformiert werden soll. Da unsere Weltkoordinaten den Ursprung (0,0) nicht unbedingt links unten haben müssen - es könnte ja auch negative Koordinaten geben, habe ich auch noch die Handle xOrigin und yOrigin hinzugefügt. Sie berechnen den Nullpunkt der jeweiligen Koordinate in Devicekoordinaten um. Als Letztes folgen noch einige Hilfsfunktionen, die mit der Graphik nichts zu tun haben. Sie sind nur für unseren Chart-Stack notwendig. Die ersten beiden Handle berechnen das Minimum resp. Maximum der eingegebenen Daten in einem Feld. Und die beiden letzten sorgen dafür, daß bei Betätigung der ENTER- oder der Return-Taste ein Mausklick in einem Button simuliert wird. Ich komme weiter unten noch einmal darauf zurück. Balkendiagramme
Jetzt werden die beiden letzten Handle unseres Backgroundscripts verständlich: Wenn die Return- oder Enter-Taste gedrückt wird, soll ein Mausklick in den Button mit der dicken Umrandung simuliert werden. Dessen Position habe ich einfach in der Messagebox abgefragt:
the loc of cd button "Bar Chart"gab mir die Koordinaten (111, 316) zurück. Sie werden vermutlich etwas andere Koordinaten bekommen und können dann diese im Background-Script einsetzen. Eine andere Möglichkeit ist, den Knopf auf diesen Punkt zu positionieren. Geben Sie dazu einfach in der Messagebox ein:
set the loc of cd button "Bar Chart" to 111, 316und wie von Zauberhand springt der Knopf dorthin. Dies ist die bessere Lösung, da ja auch die "Default-Buttons" der anderen beiden Karten mit diesem Background-Script funktionieren sollen. Wir werden sie später auch auf den loc (111, 316) setzen. The loc gibt immer den Mittelpunkt eines Objektes zurück und besteht daher aus einem Koordinatenpaar (zwei Items). Daneben existiert noch the rect, das die Koordinatenpaare des das Objekt umschließenden Rechtecks mit den Koordinaten links oben und rechts unten zurückgibt (vier Items). Diese beiden Möglichkeiten, die Position eines Objektes zu identifizieren oder festzulegen, werden häufig verwechselt und führen dan zu Verwirrungen und zu Programmfehlern. Falls also ein Objekt verschoben erscheint, prüfen Sie immer erst einmal nach, ob loc oder rect wirklich korrekt angewandt wurden. Nun aber zu unserem Button-Script (Listing 2): Das mouseUp Handle beinhaltet nichts Aufsehenerregendes. Die Graphik wird initialisiert. Da Balkendiagramme selten negative Werte beinhalten, werden die Achsen an der unteren und linken seitlichen Begrenzung der Grafik gezeichnet. Außerdem werden die Achsen beschriftet. Dabei wird zum ersten Mal die Funktion maxLines() benutzt, die uns die maximalen Werte der Felder xValue und yValue liefert. Hier hat der Umstand, daß HyperTalk nur einen Datentyp kennt, einmal einen Vorteil. Obwohl die Werte nach unserem Verständnis numerische Werte sind, gibt HyperTalk sie ohne weiteres als Text aus. (Intern kennt HyperTalk sowieso nur den Datentyp "Text"!) Wer je einmal in PASCAL oder MODULA eine RealToString-Funktion schreiben mußte, wird dies zu schätzen wissen. (Auf der anderen Seite wollen wir aber nicht vergessen, daß die Möglichkeit, strukturierte Datentypen zu benutzen, viele Vorteile hat und zur Sicherheit und besseren Lesbarkeit von vielen Programmen beiträgt.) Jetzt wollen wir aber unsere Balken füllen, daher das Kommando
set filled to TRUE(der Defaultwert ist FALSE). Das ist eigentlich schon alles. Interessanter ist das Handle drawBars, der von mouseUp aufgerufen wird. Hier werden zuerst die Anzahl der Balken berechnet und dann deren Weite bestimmt, so daß sie alle in unsere 300 x 300 Pixel große Zeichenfläche passen. Dann wird ein Abstand zwischen den einzelnen Balken ebenfalls in Abhängigkeit von der Balkenanzahl berechnet. Und schließlich wird die Prozedur Scale aufgerufen, die uns die Skalierungsfaktoren liefert. Dann werden die einzelnen Balken gezeichnet und mit einer Füllung versehen. Rein aus ästhetischen Gründen habe ich die Füllung ab Pattern 12 gewählt, Pattern 13 und die folgenden schienen mir für die Darstellung der Balken die geeignetsten zu sein. Das Beschriften der Balkendiagramme habe ich wegen der Übersicht in eine eigene Prozedur ausgelagert, dies ist aber nicht unbedingt nötig. Und bitte beachten Sie, das am Ende des mouseUp-Handles mit closeGraph alles wieder ordentlich zurückgesetzt wird. Liniendiagramme
Eine weitere Neuheit von HyperCard 2.3 sind die beiden (Card-) Buttons "Achsenkreuz" und "Achsen an der Seite". Sie haben den Style "Radio Button" und gehören einer "Familie" (in unserem Fall der Familie Nr. 1) an. Die Zuordnung zu einer Familie sorgt dafür, daß sich Radio Buttons auch so verhalten, wie es ein Macintosh-Anwender gewohnt ist: Nur einer der beiden Knöpfe kann gedrückt sein (Hilite of me is TRUE). Um die Zugehörigkeit der beiden Knöpfe zu einer Familie zu unterstreichen, habe ich eine Rahmen drumherum gezogen. Hier tritt eine Schwierigkeit auf: initGraph löscht jede Graphik! Daher besteht dieser Rahmen aus einem leeren Card Field mit dem Stil Rectangle, das mit Hilfe des "Send Farther" Menüs (im Menü Objekts) nach hinten hinter die beiden Buttons gebracht wurde. Warum nun diese beiden Radio Buttons? Einmal natürlich, um deren Funktionalität zu demonstrieren. Auf der anderen Seite aber auch, um zwei verschiedene Sorten von Liniendiagrammen auf einer Karte unterbringen zu können. Liniendiagramme können oft auch negative x- oder y-Werte aufweisen. Dann sollte ein Achsenkreuz gezeichnet werden. Oft aber auch will man rein positive Werte darstellen, wie z.B. die Werte aus unserer Abbildung mit dem Balkendiagrammen. Versuchen Sie doch einmal, diese Werte mit der Option Achsenkreuz zu zeichnen! Vom Jahre 0 bis 1989 (also fast auf dem gesamten Diagramm) passiert nichts - nur auf den letzten paar Pixeln versucht HyperCard verzweifelt, unsere Linien zu zeichnen. Nun zum Script selber (Listing 3): Wegen der ständigen Abfrage, welcher der beiden Radio Buttons gedrückt ist und der damit zusammenhängenden Frage, ob die Maximum- und Minimumwerte von x oder y negativ, Null oder positiv sind, habe ich die gesamte Funktionalität im mouseUp-Handle gelassen. Eine Auslagerung, wie im "Bar Chart"-Script hätte für meinen Geschmack zu viele globale Parametervereinbarungen bedeutet. Nur das Zeichnen der Punkte als kleine Kreise und das Verbinden der Punkte wurden (das es auch für andere Anwendungen einmal nützlich sein könnte (man sollte schließlich auch an die Wiederverwendung von Software denken) als eigene Handles ausgelagert. Technisch gesehen birgt dieses Script nicht viel Neues: Mit allen darin vorkommenden Sprachelementen sollten sie mittlerweile vertraut sein. Etwas trickreich ist nur die Beschriftung der Achsen - hier können Sie sehen, warum ich im Background-Script xOrigin und yOrigin getrennt berechnen lasse. Tortendiagramme
Erst einmal wird in dem mouseUp-Handle das Feld yValue aufsummiert. Tortendiagramme werden traditionsgemäß mit Prozentwerten beschriftet, und um diese auszurechnen, brauchen wir nun einmal die Gesamtsumme. Dann wird, um die Ausführung zu beschleunigen, der Wert von 2[[pi]] in eine Konstante gepackt. Dieser Wert wird in einer Schleife mehrmals benötigt, und das jeweilige neue Ausrechnen würde nur unnötig Rechenzeit vergeuden. Um die Torte, resp. deren Umriß, selber zu zeichnen, habe ich ein eigenes Handle drawCircle geschrieben. Dieses zeichnet einen Kreis mit dem Oval Tool in der gewohnten Notation Mittelpunkt (x, y) und Radius. Da Sie diese Funktion vermutlich in Ihrem Leben als HyperTalk-Programmierer immer wieder einmal brauchen, lohnt sich das Anlegen eines eigenen Handles schon. Die einzelnen Kreissegmente werden ab 0deg. (drei Uhr) in den Kreis eingezeichnet und laufen entgegen dem Uhrzeigersinn, da die weiteren Winkel mit Hilfe der bekannten Winkelfunktionen aus der Geometrie
set pattern to 12 + 2*ijedes zweite Füllmuster ausgewählt (also 14, 16, 18 etc.). Die Beschriftung der einzelnen Kreissegmente mußte in einer separaten Schleife erfolgen. Ursprünglich hatte ich alles in einem Durchgang erledigen wollen. Bei kleinen Kreissegmenten jedoch läuft die Beschriftung über die Umrandung hinaus, hierdurch entsteht ein Leck im Tortenstück, durch das der Farbeimer seine Füllung über die ganze Karte verteilt. So werden stattdessen erst die Segmente sauber gefüllt und hinterher (wenn bildlich gesprochen die Farbe getrocknet ist) erfolgt die Beschriftung. Auch bei der Beschriftung gibt es einige Neuheiten. So wird mit dem Befehl
set the numberFormat to 0.##die Anzahl der Nachkommastellen auf zwei begrenzt. Und außerdem lernen wir den Operator "&&" kennen, der zwei Strings miteinander verbindet. Während der schon bekannte Operator "&" die Zeichenketten unmittelbar aneinanderhängt ("Bier" & "durst" ergibt "Bierdurst"), fügt der Operator "&&" eine Leerstelle dazwischen: "Indiana" && "Jones" wird zu "Indiana Jones". Verbesserungen? - Verbesserungen!Das wäre es für dieses Mal. Natürlich ist dieser Stack nicht vollkommen. Eine mögliche Fehlerquelle wäre, daß bei Bar Chart und Line Chart eigentlich die Werte in xValue daraufhin geprüft werden müßten, ob sie aufsteigend sortiert sind (bei Bar Chart würde eine andere Sortierung zwar nicht zu Fehlern, aber zu Irritationen des Lesers führen). Die Leserin oder der Leser sind aufgefordert, eine Sortierung für dieses Feld zu programmieren. HyperTalk hält dafür den leistungsstarken Befehl "sort" bereit, der Karten, Zeilen oder Items sortieren kann. Und Line Chart könnte von Ihnen zu einem Funktionenplotter erweitert werden, der Funktionen der Art y = f(x) zeichnet, die Ihnen sicherlich noch aus der Schule bekannt sind. |
|||||
© 1996 - 2001 by Jörg Kantel Last modified: JK, 04.09.2001; 20:33:27 Uhr email:joerg@kantel.de |