2.2 Ausgabe von GrafikGrafische Ausgaben auf den Schirm gehören zu den Kernaufgaben einer Programmiersprache. R-BASIC bietet diesbezüglich eine Fülle von Möglichkeiten. In diesem Kapitel finden Sie einen Überblick über die Möglichkeiten und die dazu verwendeten Objekte. Unter R-BASIC erfolgt die Ausgabe von Grafik - das schließt Textausgaben mit der Anweisung PRINT ein - immer auf das aktuelle 'Screen' Objekt. Mehr zu Screenobjekt finden sie im Kapitel 2.3 unten.2.2.1 Objekte zur Grafikausgabe ^2.2.1 Objekte zur GrafikausgabeIm Folgenden werden die zur Grafikausgabe verwendbaren Objektklassen aufgezählt und ihre Vor- und Nachteile unter dem Aspekt der Grafik- und Textausgabe gegenübergestellt. Eine ausführliche Beschreibung der einzelnen Objektklassen finden sie in den folgenden Kapiteln des Objekthandbuchs.
BitmapContentEin BitmapContent (Container für eine Bitmap) stellt eine Bitmap bereit, in die man Grafik und Text zeichnen kann. Üblicherweise ist das BitmapContent Objekt als 'Content' eines View Objekts gesetzt. Das ist notwendig, um die Bitmap auf den Schirm zu zeichnen, aber es ist ausdrücklich erlaubt auch in eine Bitmap, die nicht mit einem View Objekt verbunden ist, zu zeichnen. Die Veränderungen werden sichtbar, wenn das BitmapContent Objekt das nächste Mal mit einem View verbunden (als Content gesetzt) wird.Der große Vorteil von BitmapContent Objekten ist, dass alle Grafikausgaben automatisch gespeichert werden. Muss sich das Objekt neu darstellen erfolgt das ohne das Zutun von BASIC Code einfach durch Neuzeichnen der Bitmap. Nachteilig ist der relativ große Speicherbedarf. Außerdem kann es Farbabweichungen geben, wenn die Farbtiefe der Bitmap nicht mit der der verwendeten Zeichenbefehle übereinstimmt. Zeichnet man z.B. True-Color Grafiken in eine 8-Bit-Bitmap werden die Farben heruntergerechnet. Da Grafikausgaben aus Performancegründen immer parallel auf den Schirm und auf die Bitmap erfolgen ist dieser Effekt meist erst nach einer Neudarstellung des Objekts zu sehen, was besonders störend wirken kann.
CanvasEin Canvas Objekt zeichnet eine Grafik, indem es seinen OnDraw Handler aufruft. Dieser Handler zeichnet dann die eigentliche Grafik auf den Schirm. Das Canvas-Objekt eignet sich sehr gut für kleine, einfache Grafiken, die zur Laufzeit gezeichnet werden können und sich nicht oder nur selten ändern. Das können z.B. einfache Grafikbefehle oder ein Bild aus der Picture-List sein.Von Vorteil ist die einfache Handhabung des Objekts. Außer um das Schreiben des OnDraw Handlers muss man sich um nichts kümmern. Auch der geringe Speicherbedarf des Objekts ist unter GEOS ein Vorteil. Im normalen (ungepufferten Modus) ist nachteilig, dass der OnDraw Handler jedes Mal gerufen wird, wenn sich das Objekt neu darstellen muss, z.B. weil ein Teil des Objekts durch ein Menü verdeckt war. Das ist langsam und belastet den BASIC-Thread. Für einfache Anwendungen ist das jedoch ausreichend. Im gepufferten Modus merkt sich das Canvas-Objekt die Grafikbefehle intern als GString und spielt ihn mit hoher Geschwindigkeit wieder ab, wenn sich das Objekt neu darstellen muss.
ImageImageobjekte sind dafür ausgelegt Bilder aus eine externen Bilddatei z.B. BMP, ICO, PCX, JPG ...) darzustellen. Sie müssen dem Objekt nur Name und Speicherort der Datei mitteilen, um den Rest kümmert es sich allein. Da Imageobjekte das Bild aus der Datei intern in einen GEOS Bitmap kopieren benötigen sie ähnlich viele Speicher wie BitmapContent Objekte. Imageobjekte sind dafür ausgelegt das Bild darzustellen. Eine Bearbeitung (wie mit einem BitmapContent Objekt) ist nicht möglich.
VisContentDas VisContent Objekt wird als 'content' eines View Objekts in den Tree eingebunden. Es hat einen OnDraw-Handler, so wie ein Canvas-Objekt. Deshalb kann das VisContent-Objekt direkt Grafik und Text ausgeben. Aber üblicher Weise erledigen die Grafikausgabe die Children des VisContent-Objekts. Das sind Objekte der Klasse VisObj.
VisObjObjekte der Klasse VisObj sind die Children eines VisContent Objekts. Deswegen werden Sie immer innerhalb eines View Objekts dargestellt. Wie das Canvas-Objekt besitzen sie einen OnDraw Handler und einen gepufferten Modus. Durch die Darstellung innerhalb eines View ergeben sich Möglichkeiten, die mit einem Canvas Objekt nicht möglich sind, z.B. Scrolling und Zoom. Außerdem kann man VisObj Objekte mit der Maus positionieren.
Generic Class: Grafische CaptionsAlle von der GenericClass abstammenden Objekt können kleine (!) Grafiken als Caption darstellen (Instancevariablen CaptionImage, CaptionPicture, CaptionGString oder CaptionIcon). Gedacht ist dieses Feature für grafische Button-Beschriftungen und grafische Listenelemente, es eignet sich aber auch für Logos und andere kleine Grafiken, die zur Laufzeit nicht oder nur selten geändert werden. Wenn Sie grafische Captions zur Laufzeit verändern sollten Sie die Größe der Grafiken im Blick haben. Details dazu finden Sie im Kapitel 3.1 (Caption: Die Objekt-Beschriftung).^2.2.2 Konzepte zur GrafikausgabeDieses Kapitel enthält einen Überblick über die in R-BASIC verfügbaren Konzepte zur Grafikausgabe. Im Einzelnen sind das
Einfache grafische KommandosDem R-BASIC Programmierer stehen eine große Auswahl von einfachen grafischen Kommandos wie Line, Circle, FillEllipse usw. zur Verfügung. Diese, sowie die das dazugehörige Koordinatensystem werden ausführlich im Kapitel 2.8 (Grafik) des R-BASIC Programmierhandbuchs besprochen. Besonders hingewiesen werden soll hier auf die Systemvariable graphic, über die die Eigenschaften aller Grafikbefehle wie Linienfarbe, Linienbreite und Flächenattribute (z.B. Füllmuster) bis hin zum MixMode eingestellt werden können. Die daraus resultierenden Möglichkeiten gehen weit über die klassischen BASIC Befehle wie INK und COLOR hinaus.PRINT und BlockGrafikDer Befehl PRINT ist unter BASIC für alles, was mit Textausgabe auf den Grafikschirm zusammenhängt, zuständig. Er wird ausführlich im Kapitel 2.9 (Textausgabe) des R-BASIC Programmierhandbuchs besprochen. Welche Schriftart, Schriftgröße usw. verwendet wird, wird mit der Systemvariablen printFont kontrolliert. Wie man darauf zugreift ist im Kapitel 2 (Verwendung von Schriften)des Handbuchs 'Spezielle Themen' beschrieben. Für die Formatierung von Zahlen bei der Ausgabe mit Print oder dem BASIC Befehl Str$ ist die Systemvariable numberFormat zuständig, deren Beschreibung Sie im Kapitel 1 (Formatierung von Zahlen) des Handbuchs 'Spezielle Themen' finden.Eine spezielle, dabei sehr einfache und gleichzeitig leistungsfähige Art, Grafiken zu zeichnen, sind die sogenannten Blockgrafiken. Dabei wird der PRINT-Befehl verwendet, statt der Buchstaben werden aber kleine Grafiken (z.B. 32x32 Pixel) auf den Schirm gezeichnet. Jedem Buchstaben kann dabei eine eigene Grafik zugeordnet werden, so dass sich sehr komplexe Bilder aus wenigen Grafikelementen zeichnen lassen. Blockgrafikelemente lassen sich am einfachsten mit dem Blockgrafik Editor, der über das Tools-Menü von R-BASIC erreichbar ist, erstellen. Wie man den Blockgrafik Modus einsetzt ist im Kapitel 3 (Verwendung des Block-Grafik-Modus)des Handbuchs 'Spezielle Themen' beschrieben.
Die Picture-ListDie Picture-List ist eine komfortable Möglichkeit Grafiken im der Codedatei selbst unterzubringen um sie zur Laufzeit zu verwenden. Sie können diese Bilder auf den Screen zeichnen oder als grafische Aufschrift für Objekte verwenden. Die Picture-List wird über das Menü 'Extras' - 'Picture-List' verwaltet.Eine ausführliche Beschreibung der Arbeit mit der Picture-List finden Sie im R-BASIC Programmierhandbuch, Kapitel 2.8.6.2 (Verwendung der 'Picture-List').
Graphic StringsEin Graphic String (im Folgenden kurz GString) ist eine Folge von Grafikbefehlen oder Textausgaben, die gemeinsam gespeichert werden. Dieser GString kann später beliebig oft 'abgespielt' werden. Dabei werden die enthaltenen grafischen Kommandos mit hoher Geschwindigkeit ausgeführt, viel schneller als dies als Folge von BASIC-Anweisungen möglich ist.GStrings sind ein tief im GEOS System verwurzeltes und sehr leistungsfähiges Konzept. Beispielsweise erfolgt der Austausch von Grafiken zwischen verschiedenen Programmen über die Zwischenablage immer als GStrings. Der gepufferte Modus verschiedener BASIC Objekte (z.B. Canvas oder VisObj) ist ebenfalls mit GStrings realisiert. Unter R-BASIC können Sie GStrings für verschiedene Zwecke verwenden
Eine ausführliche Beschreibung der Arbeit mit GStrings finden Sie im R-BASIC Programmierhandbuch, Kapitel 2.8.5 (Arbeit mit Graphic Strings).
BitmapsBitmaps sind digitalisierte Bilder. Sie bestehen aus einer rechteckigen Anordnung von einzelnen Bildpunkten (Picture Element: Pixel). Jedem Pixel kann eine eigene Farbe zugeordnet werden.Innerhalb von GEOS werden Bitmaps immer im GEOS-internen Bitmapformat gespeichert, unabhängig davon, aus welcher Quelle (z.B. welchem Dateiformat) die Bilder stammen. Dieses interne GEOS Format erlaubt die Existenz einer Transparenz-Maske als auch einer Palette für jede Bitmap. Die Transparenz-Maske muss man sich als zusätzliche Farbebene vorstellen, die neben den eigentlichen Bilddaten gespeichert wird. Dabei gibt es für jedes Pixel genau ein Transparenzbit. Ist es gesetzt (=1) wird das entsprechende Pixel des Bildes dargestellt. Ist es nicht gesetzt (=0) ist das Bild an dieser Stelle durchsichtig. Viele Bilder enthalten weniger als 3 Byte (24 Bit) pro Pixel. Ein üblicher Wert ist z.B. 8 Bit pro Pixel. Das spart Speicher. Aber damit können sie nur 256 der 16 Mio. möglichen Farben darstellen. Welche das sind, kann mit einer Palette festgelegt werden. Jeder Paletteneintrag besteht aus genau 3 Byte. Damit wird jedem möglichen Farbwert des Bildes (0 ... 255 bei 8 Bit pro Pixel) eine True-Color Farbe zugeordnet. Durch eine geschickte Wahl der Palette kann man sehr realistische Bilder erzeugen. Enthält ein Bild mit 8 Bit pro Pixel keine Palette wird die GEOS Standardpalette verwendet. Diese Bilder werden etwas schneller gezeichnet, aber viele Probleme mit der Farbdarstellung entstehen deswegen, weil die Windows-Standardpalette nicht mit der GEOS-Palette identisch ist. Es ist deshalb oft eine gute Idee 256-Farb-Bilder in die GEOS Palette umzurechnen. Dazu eignet sich z.B. das GEOS Tool Sigma. In R-BASIC erfolgt die Verwaltung einer Bitmap üblicher Weise mit einem BitmapContent Objekt. Dieses Objekt kümmert sich selbständig um den benötigten Speicherplatz sowie um die Darstellung der Bitmap auf dem Schirm. Es ermöglicht es in die Bitmap zu zeichnen oder Farbwerte auszulesen und bietet außerdem Funktionen zum Bearbeiten der Transparenz-Maske und der Palette. Eine Beschreibung des BitmapContent Objekts finden Sie weiter hinten im Objekthandbuch. Dort sind auch die Strukturen von Bitmap, Transparenz-Maske und Palette beschrieben. Zusätzlich bietet R-BASIC die Möglichkeit Bitmaps analog zu den GStrings über Handles anzusprechen. Über diesen Weg können Bitmap zwischen Teilen des BASIC Programms ausgetauscht und in andere Bitmaps oder in GStrings gezeichnet werden. Die R-BASIC Library 'VMFiles' bietet außerdem Funktionen an, Bitmaps in eine Datei zu schreiben bzw. ihn von dort zu laden. Der Bitmapzugriff über Handles ist ausführlich im Anschnitt 2.8.6.4 (Bitmaps und Bitmap Handles) des R-BASIC Programmierhandbuchs beschrieben.
2.3 Arbeit mit dem ScreenSowohl alle Grafik-Befehle als auch der Print-Befehl müssen wissen, wohin die Ausgaben erfolgen sollen. Dieses Ausgabe-Ziel ist ein Objekt, das als Screen-Objekt bezeichnet wird. Als Screen-Objekte können folgende Objekte dienen:
Zusätzlich können Sie die genannten Objekte jederzeit temporär zum Screen machen, indem Sie die Screen-Variable mit dem Objekt belegen. Das ist z.B. bei der Arbeit mit der Maus sinnvoll. Sie müssen sich in diesem Fall aber selbst darum kümmern, dass der zuvor gesetzte Screen wieder hergestellt wird, sonst kann GEOS crashen. Beispiele dazu finden Sie in den Kapiteln zur Arbeit mit der Maus (Spezielle Themen, Kapitel 17) und bei der Beschreibung der Objektklassen VisContent und VisObj (Kapitel 5 im Objekthandbuch). Sie können in R-BASIC zwischen verschiedenen globalen Screen-Objekten wechseln. Außerdem können Sie Einstellungen am Koordinatensystem wie Skalierung und Verschiebung vornehmen. Erfahrene Programmierer haben außerdem die Möglichkeit komplexe Operationen mit dem Koordinatensystem durchzuführen.
2.3.1 Die Screen-Variable
Syntax Lesen: <objVar> = Screen Schreiben: Screen = <obj> Am Programmstart wird die Variable Screen mit demjenigen Objekt belegt, dass die Anweisung DefaultScreen im UI-Code hat. Die Anweisung DefaultScreen ist nur für BitmapContent Objekte zulässig. Syntax UI-Code: DefaultScreen Wird ein Objekt erstmalig zum Screen, so werden alle Grafik- und Font-Ein-stellungen auf den Standardwert zurückgesetzt, das Ausgabe-Window wird auf Maximum gesetzt und der Cursor wird links oben platziert. Die Farben werden auf die durch den defaultColor-Wert des neuen Screen-Objekts bestimmten Werte gesetzt. Ist kein defaultColor-Wert spezifiziert wird Schwarz auf Weiß eingestellt. Verliert ein Objekt den Status 'Screen' zu sein, so speichert es die genannten Werte intern und stellt sie wieder her, wenn es erneut zum Screen wird. Sollte das nicht möglich sein, weil Sie z.B. zwischenzeitlich die Bitmapgröße geändert haben, werden wieder die Standardwerte verwendet. Beispiel: Umschalten zwischen den beiden Objekten MyContent1 und MyContent2 | |||||||||
IF Screen = MyContent1 THEN Screen = MyContent2 ELSE Screen = MyContent1 END IF | |||||||||
|
Wird die Variable Screen mit einem 'leeren' Objekt belegt ( Funktion NullObj() ), so gehen alle Grafik- und Textausgaben ins Leere.
Beispiel 1: | |||||||||
Screen = NullObj() | |||||||||
| Beispiel 2: | |||||||||
IF Screen = NullObj() THEN Screen = MyContent1 | |||||||||
^2.3.2 ClippingUnter Clipping versteht man, dass Grafiken und Texte nicht über die vorgegeben Geometriegrenzen hinaus geschrieben werden. Beim Zeichnen in eine Bitmap wird nicht über deren Rand hinaus gezeichnet, Objekte die in einem View-Objekt sind zeichnen nicht über die Grenzen des View hinaus. GEOS und damit R-BASIC handelt das automatisch, so dass Sie sich im Allgemeinen nicht darum kümmern müssen. Sie haben jedoch die Möglichkeit den Bereich, in den Grafik- und Textausgaben gehen sollen, zusätzlich einzuschränken.ScreenSetClipRectDie Routine ScreenSetClipRect schränkt die Ausgabe von Grafik und Text auf den angegeben Koordinatenbereich ein.Syntax: ScreenSetClipRect x0, y0, x1, y1 x0, y0: linke obere Ecke des Clip-Rechtecks x1, y1: rechte untere Ecke des Clip-Rechtecks Beispiel: | |||||||||
Paper LIGHT_BLUE CLS ScreenSetClipRect 50, 50, 150, 150 FillEllipse 15, 15, 85, 85, BLUE FillEllipse 115, 115, 185, 185, GREEN Rectangle 50, 50, 150, 150, black ScreenSetClipRect 125, 25, 225, 125 Paper LIGHT_CYAN CLS FillEllipse 105, 5, 175, 80, YELLOW FillEllipse 175, 75, 295, 195, LIGHT_GREEN Rectangle 125, 25, 225, 125, BLACK | |||||||||
|
Hinweise:
^2.3.3 Speichern und Wiederherstellen des Screen-StatusGelegentlich gibt es die Situation, dass man Änderungen in den Einstellungen für Grafik und/oder Text (Farben, Font, Linienbreite ...) vornehmen will, die aber anschließend wieder zurückgenommen werden sollen. Oft passiert das innerhalb einer Routine oder in einem Action-Handler, der Grafiken ausgibt aber sicherstellen will, dass die aktuell Screen-Einstellungen nicht verändert werden. Die Anweisung ScreenSaveState speichert alle den Screen betreffenden Einstellungen - mit Ausnahme der BlockFonts und des Clipping-Rechtecks. ScreenRestoreState stellt den gesicherten Zustand wieder her. Alle zwischenzeitlich vorgenommenen Änderungen für Text und Grafik gehen verloren.ScreenSaveState kann mehrfach hintereinander aufgerufen werden, die Einstellungen werden von ScreenSaveState jeweils in einen eigenen Speicherbereich kopiert und von ScreenRestoreState in der umgekehrten Reihenfolge wieder restauriert. Dieses Vorgehen stellt sicher, dass eine Routine die Kombination ScreenSaveState / ScreenRestoreState verwenden kann, unabhängig davon, ob andere Routinen dies auch tun. Beispiel: Die Routine zeichnet einen blauen Kreis ohne die aktuell eingestellten Linieneigenschaften zu verändern. | |||||||||
SUB BlueCircle ( x, y as integer ) ScreenSaveState graphic.lineColor = BLUE graphic.lineWidth = 4 Circle x, y, 50 ScreenRestoreState END SUB | |||||||||
ScreenSaveStateSpeichert die aktuellen Einstellungen für Grafik und Text.Syntax: ScreenSaveState Parameter: keine ScreenRestoreStateStellt die Einstellungen für Grafik und Text wieder her. Jede Routine muss genau so viele ScreenRestoreState wie ScreenSaveState aufrufen.Syntax: ScreenRestoreState Parameter: keine Hinweise:
^2.3.4 Anpassen des KoordinatensystemsIn diesem Abschnitt werden Routinen beschrieben, die einfache Operationen mit dem Koordinatensystem durchführen. Dabei handelt es sich um Verschiebung, Skalierung und Rotation. Diese Operationen werden als Koordinatentransformationen bezeichnet. Sie wirken immer auf die nachfolgenden Grafik- oder Text-Ausgaben. Bereits vorhandene Grafiken oder Texte werden nicht beeinflusst.Werden mehrere Transformationen nacheinander ausgeführt, so berechnet GEOS intern eine 'resultierende' Transformation, so dass es für die Performance keinen Unterschied macht wie viele Transformationen angewendet wurden. Beachten Sie, dass die Reihenfolge der Transformationen wichtig ist, es ist etwas anderes ob man erst verschiebt und dann rotiert oder umgekehrt (siehe Beispiel unten). Normalerweise begrenzt die PRINT-Anweisung die Ausgabe von Texten auf die ursprünglichen Koordinaten des Screens. Wenn Sie das Koordinatensystem geändert, z.B. nach rechts unten verschoben haben, kann Print z.B. den Zugriff auf Bereiche links und oberhalb des neuen Nullpunkts (negative Cursor-Koordinaten) verweigern. Sie müssen dann in den LAYOUT-Modus wechseln, in dem alle Cursor-Restriktionen, allerdings auch der automatische Zeilenumbruch, deaktiviert sind. Verwenden Sie dazu die Anweisung: | |||||||||
Print Chr$(19) 'oder gleichwertig Print "\19" | |||||||||
Print Chr$(17) ruft den PAGE-Modus auf, Print Chr$(18) den Scroll-Modus.
ScreenSetTranslationVerschiebt den Ursprung des Koordinatensystems (Lage des Koordinatenursprungs) um die angegebenen Werte.Syntax: ScreenSetTranslation xMove, yMove xMove: Verschiebung in x-Richtung yMove: Verschiebung in y-Richtung ScreenSetScaleSkaliert die Achsen des Koordinatensystems um die angegebenen Werte. Negative Werte sind zulässig, sie bewirken eine Spiegelung in der entsprechenden Richtung. Bezugspunkt ist immer der aktuelle Koordinatenursprung.Syntax: ScreenSetScale xScale, yScale xScale: Streckung in x-Richtung yScale: Streckung in y-Richtung ScreenSetRotationRotiert das Koordinatensystem um den angegebenen Winkel. Die Drehung erfolgt um den aktuellen Koordinatenursprung
Syntax: ScreenSetRotation alpha
alpha: Drehwinkel im Gradmaß
Drehung erfolgt gegen den Uhrzeigersinn
Beispiel: Drehung um 45° nach rechts | |||||||||
ScreenSetRotation -45 | |||||||||
ScreenResetTransformationNimmt alle Koordinatentransformationen zurück. Der Koordinatenursprung wird nach links oben gesetzt, Drehung und Skalierung werden zurückgesetzt.Syntax: ScreenResetTransformation Beispiel 1: Unterschiedliche Transformationen. Textausgabe ohne Transformation: | |||||||||
FontSetGeos( FID_CRANBROOK, 20 ) Print "Life is "; Print "an adventure."; Rectangle 220, 0, 250, 30 | |||||||||
|
Gedrehte und skalierte Text-Ausgabe, die Reihenfolge spielt eine Rolle! | |||||||||
FontSetGeos( FID_CRANBROOK, 20 ) Print "Life is "; ScreenSetScale 1, 1.7 ' y: 170% ScreenSetRotation -20 ' 20° im Uhrzeigersinn Print "an adventure."; Rectangle 220, 0, 250, 30 | |||||||||
|
1. Bild: Erst skaliert, dann rotiert (wie im Code gezeigt)
Beispiel 2: Translation und Rotation.
| |||||||||
graphic.linewidth = 3
Line -70, 0, 70, 0, YELLOW
Line 0, -30, 0, 30, YELLOW
ScreenSetRotation -30
Line -70, 0, 70, 0, LIGHT_CYAN
Line 0, -30, 0, 30, LIGHT_CYAN
ScreenSetTranslation 150, 0
Line -70, 0, 70, 0, LIGHT_RED
Line 0, -30, 0, 30, LIGHT_RED
Print at 1,1;"Rot + Trans"
ScreenResetTransformation ' wieder Ausgangssituation
' herstellen
ScreenSetTranslation 150, 0
Line -70, 0, 70, 0, LIGHT_GRAY
Line 0, -30, 0, 30, LIGHT_GRAY
ScreenSetRotation -30
Line -70, 0, 70, 0, WHITE
Line 0, -30, 0, 30, WHITE
Print at 1,1;"Trans + Rot"
| |||||||||
|
2.3.5 Komplexe Manipulation des KoordinatensystemsHinweis: Dieses Kapitel ist etwas für erfahrene und mathematisch versierte Programmierer. Die meisten Programmierer werden niemals mit den hier dargestellten Zusammenhängen arbeiten.Wie bereits oben erwähnt berechnet GEOS bei Anwendung mehrerer Koordinatentransformationen eine 'resultierende' Transformation. Dazu wird intern die Matrizenrechnung verwendet, die dazugehörige Struktur heißt Transformationsmatrix. Sie können die Transformationsmatrix lesen, verändern, eine eigene erstellen und sie wieder setzen. Dieses Kapitel beschreibt die dazugehörigen Routinen ScreenGetTransMatrix, ScreenSetTransMatrix, die Struktur TransMatrix und die mathematischen Grundlagen. Jedes Mal, wenn GEOS einen einzelnen Punkt mit den Koordinaten (x; y) auf dem Bildschirm darstellt, wendet es die aktuell gültige Transformationsmatrix auf diesen Punkt an, um die Bildschirmkoordinaten (x'; y') zu erhalten. Dieses Verfahren wird für jeden einzelnen Punkt einer Linie, eines Buchstabens usw. angewendet. Diese Berechnungen sind für eine schnelle Grafikausgabe optimiert und in GEOS extrem effizient implementiert. In Matrizenschreibweise sieht das so aus:
Im Einzelnen berechnen sich die neuen Koordinaten somit folgendermaßen: x' = a1 * x + b1 * y + c1 y' = b1 * x + b2 * y + c2Beispiele für Transformation-Matrizen:
Wird eine neue Koordinatentransformation angewendet (z.B. mit ScreenSetTranslation), so berechnet GEOS das Kreuzprodukt der alten Transformationsmatrix mit der neuen, wobei sich eine resultierende Transformationsmatrix ergibt, die alle bereits vorhandenen und die neue Koordinatentransformation enthält. Am Rechenaufwand bei der Darstellung auf dem Bildschirm, d.h. an der Ausgabegeschwindigkeit ändert sich dadurch nichts. Erfahrene oder ambitionierte Programmierer können ihre eigene, komplexe Transformationsmatrix erstellen und diese mit ScreenSetTransMatrix anwenden. Oder man sichert die aktuelle Transformationsmatrix mit ScreenGetTransMatrix um sie später wieder zu verwenden. Dabei ist es erlaubt die Transformationsmatrix von einem Screen-Objekt zu lesen und einem anderen Screen-Objekt zuzuweisen. Die Struktur TransMatrix enthält die 6 variablen Elemente der Transformations-Matrix und ist in R-BASIC folgendermaßen definiert: | |||||||||
STRUCT TransMatrix a1, b1, c1 AS REAL a2, b2, c2 AS REAL END STRUCT | |||||||||
ScreenGetTransMatrixLiest die aktuell gültige Transformationsmatrix des aktuellen Screen-Objekts aus. Die Klammern sind erforderlich, da es sich um eine Funktion handelt, d.h. sie liefert einen Wert zurück. Ist kein Screen-Objekt gesetzt ist das Ergebnis unbestimmt und sollte nicht verwendet werden.Syntax: <tm> = ScreenGetTransMatrix ( ) <tm>: Variable vom Typ TransMatrix ScreenSetTransMatrixWendet eine Transformationsmatrix auf den aktuellen Screen an. Ist kein Screen-Objekt gesetzt wird die Operation ignoriert.Syntax: ScreenSetTransMatrix ( <tm> ) <tm>: Variable oder Ausdruck vom Typ TransMatrix 2.4 Objekte individualisierenDer folgende Abschnitt setzt voraus, dass Sie sich bereits etwas im GEOS Objektsystem auskennen und auch mit der Verwendung von Strukturen vertraut sind.Es gibt Situationen, in denen es nötig ist, dass ein Objekt neben den vom System vorgegebenen Daten weitere Informationen speichern muss. Ein einfaches Beispiel ist ein Canvas-Objekt, dass entweder einen Kreis oder ein Quadrat zeichnen soll. Sie können die Information, ob ein Kreis oder ein Quadrat gezeichnet werden soll, natürlich für jedes Objekt in einer eigenen globalen Variablen speichern. Das ist aber nicht nur schlechter Stil, sondern wird bei mehreren Objekten auch schnell sehr unübersichtlich und damit fehlernfällig. Die bessere Lösung ist, die Information im Objekt selber zu speichern. R-BASIC bietet Ihnen für diese Situation die Instancevariable privData. PrivData nimmt eine Strukurvariable beliebigen Typs auf und speichert sie im Objekt selbst. Hier können Sie z.B. ablegen, ob ein Kreis oder ein Quadrat gezeichnet werden soll. Außerdem können Sie - wenn Sie wollen - die Größe, die Farbe und beliebige weitere Informationen speichern. VisObj-Objekte haben zusätzlich die Instancevariable visDataValue. Sie enthält einen numerischen Wert (LongInt-Bereich), mit dem Sie bei Bedarf verschiedene VisObj-Objekte auseinanderhalten können, ohne auf die relativ umständliche Verwendung der Instancevariablen privData zurückzugreifen. Außerdem können Sie visDataValue bereits im UI-Code zuweisen. Fortgeschrittene Programmierer können in seltenen Situationen den Bedarf haben, dass sie eine Routine erst dann aufrufen wollen, wenn der aktuelle Actionhandler vollständig abgearbeitet ist. Typische Beispiele sind hier der OnPrint Handler (bei dem man das Screen-Objekt nicht ändern darf) oder ein OnMouse~ bzw. der OnKeyPressed Handler (die meist zeitkritisch sind). R-BASIC löst dieses Problem, indem man für Objekte eigene, private ('custom') Handler definieren kann. Actionhandler unterbrechen sich niemals, sondern werden immer nacheinander abgearbeitet. Der Aufruf eines solchen Handlers führt also dazu, dass die aktuelle Routine (genauer: der komplette aktuell laufende Handler) zuerst vollständig abgearbeitet wird bevor der neue Handler ausgeführt wird. Um einen Custom Handler für ein Objekt festzulegen verwenden Sie die Instancevariable customHandler. Custom Handler müssen als CustomAction deklariert sein. Um einen Custom Handler aufzurufen verwenden Sie die Methode CustomApply.
PrivDataPrivData nimmt eine einzelne Strukturvariable (also maximal 3500 Bytes) auf. Diese Instancevariable ist für alle Klassen definiert. PrivData ist zuweisungskompatibel mit jeder Art von Struktur, es wird weder eine Typ- noch eine Größenprüfung ausgeführt. Es ist daher vernünftig beim Schreiben und beim Lesen der Daten den gleichen Struktur-Datentyp zu verwenden.Schreiben: Sie müssen die Größe der zu schreibenden Daten angeben. Lesen:Es werden so viele Bytes gelesen, wie die Variable auf der linken Seite der Zuweisung aufnehmen kann. Enthält privData weniger Bytes, so wird der Rest mit Nullen aufgefüllt. Es ist zulässig, mehrfach hintereinander Strukturen verschiedenen Typs und verschiedener Größe in die Instancevariable zu schreiben. R-BASIC optimiert jedes Mal den verwendeten Speicher, so dass kein Platz verschwendet wird.
Syntax Schreiben: <obj>.privData = <struct>, size
<struct>: Strukturausdruck beliebigen Typs
size: Größe der Struktur
Lesen: <sturctVar> = <obj>.privData
<structVar>: Strukturvariable des Typs, der beim Schreiben verwendet wurde.
Beispiel: Ein Canvas-Objekt soll einen Kreis oder ein Quadrat in einer vorgegebenen Farbe zeichnen. Wir benötigen:
| |||||||||
STRUCT ImgData isCircle as Integer color as Integer End Struct | |||||||||
| Zum Belegen der Instancewerte dient die folgende Routine. Die zweite Routine (SetCanvasToRect) ist hier nicht aufgeführt. | |||||||||
SUB SetCanvasToCircle( col as Integer) DIM pd AS ImgData pd.isCircle = TRUE pd.color = col MyCanvas.privData = pd, SIZEOF(pd) MyCanvas.Dirty ' Neudarstellung auslösen End Sub | |||||||||
| Das Canvas-Objekt sei wie folgt definiert. Beachten Sie, dass wir privData nicht definieren brauchen, es ist für alle Objekte automatisch verfügbar. | |||||||||
CANVAS MyCanvas OnDraw = DrawFigure fixedSize = 70, 70 End Object | |||||||||
| Schließlich benötigen wir noch den OnDraw-Handler, der die privData-Werte ausliest und verwendet. | |||||||||
DRAWACTION DrawFigure
DIM priv as ImgData
priv = sender.privData
INK priv.col
IF priv.isCircle THEN
FillEllipse 10, 10, 60, 60
ELSE
FillRect 10, 10, 60, 60
END IF
End Action
| |||||||||
CustomHandlerCustomHandler enthält den Namen des Actionhandlers, der mit der Methode CustomApply aufgerufen werden soll.
Syntax UI-Code: CustomHandler = <Handler>
Schreiben: <obj>.CustomHandler = <Handler>
Ein Custom Handler muss als CustomAction deklariert sein:
CustomApplyDie Methode CustomApply ruft den CustomHandler eines Objekts auf. Ihr wird ein Integer-Wert übergeben, der an den Handler weitergereicht wird.
Syntax: <obj>.CustomApply actionData
actionData: Integerwert, der an CustomHandler übergeben wird.
Beispiel (einfach, deswegen nicht sehr sinnvoll): Ein Button mit einem ActionHandler und Primary mit einem CustomHandler. | |||||||||
BUTTON MyButton Caption$ "Drück mich!" ActionHandler = PressHandler End Object Primary MyPrimary CustomHandler = CHandler End Object | |||||||||
| Der Actionhandler: | |||||||||
ButtonAction PressHandler Print "Text 1" MyPrimary.CustomApply 1 Print "Text 2" MyPrimary.CustomApply -7 Print "Text 3" End Action | |||||||||
| Der CustomHandler wird erst ausgeführt, wenn der ActionHandler fertig ist. | |||||||||
CustomAction CHandler
Print "DATA = ";actionData
End Action
| |||||||||
| Wenn der Nutzer den Button drückt, erscheint folgendes: | |||||||||
Text 1 Text 2 Text 3 DATA = 1 DATA =-7 | |||||||||
^ |