4.16 Canvas

Überblick

Ein Canvasobjekt (engl: Leinwand) dient dazu, eine Grafik anzuzeigen. Diese Grafik liegt nicht als vorgefertigtes Bild vor, sondern wird zur Laufzeit gezeichnet. Bei Bedarf kann sich die vom Canvasobjekt angezeigte Grafik also ändern. Dazu verfügt das Canvas Objekt über folgende Fähigkeiten:

  • OnDraw Handler: Dieser Handler wird gerufen, wenn sich das Objekt auf dem Bildschirm darstellt. Der OnDraw Handler zeichnet die Grafik.

  • Gepufferte Darstellung: Wenn gewünscht kann das Objekt die Grafik, die der OnDraw Handler gezeichnet hat, intern abspeichern. Sie kann dann abgerufen werden ohne den OnDraw Handler erneut auszuführen. Das ist wesentlich schneller und geht auch, wenn Ihr Programm gerade mit anderen Operationen beschäftigt ist.
Innerhalb des OnDraw Handlers wird das Canvasobjekt automatisch zu Screen, so dass Grafik und Text einfach ausgegeben werden können. Für viele Zwecke ist das nicht nur ausreichend, sondern auch die bessere Wahl. In Vergleich zu einem BitmapContent-Objekt benötigt das Canvasobjekt viel weniger Speicher, da es keine Bitmap im Hintergrund verwaltet. Und es benötigt kein Viewobjekt als Partner, ist also einfacher zu handhaben.

Verwenden Sie ein Canvasobjekt, wenn Sie eine einfache Grafik, z.B. ein Logo, ein Schema oder einen grafisch gestalteten Text, darstellen wollen, die sich im Programmablauf nicht oder nur selten ändern. Für grafische Ausgaben, die während des Programmablaufs ständig angepasst werden müssen, wie Statusmeldungen (z.B. "Schritt 5 von 10") oder bewegte Grafiken ist das Canvasobjekt nicht optimal. Beispiele zur Verwendung des Canvas-Objekts finden Sie im Ordner "Beispiel\Objekte\Grafik".

Abstammung:

...

Das Canvasobjekt erbt alle Eigenschaften und Fähigkeiten der GenericClass. Von besonderer Bedeutung sind dabei die Fähigkeiten zum Geometriemanagement (siehe Kapitel 3.3). Insbesondere die Hints fixedSize, initialSize, ExpandWidth und/oder ExpandHeight werden häufig genutzt, da das Canvas Objekt "von sich aus" keine vorgegebene Größe hat und sonst möglicherweise unsichtbar klein ist.

Spezielle Instance-Variablen:

Variable Syntax im UI-Code Im BASIC-Code
OnDraw OnDraw = <Handler> nur schreiben
defaultColor defaultColor = fg, bg lesen, schreiben
buffered buffered = TRUE lesen, schreiben
bufferedDataSize bufferedDataSize = <Wert> lesen, schreiben

Methoden:

Methode Aufgabe
Dirty Weist das Objekt an, sich neu darzustellen

Action-Handler-Typen:

Handler-Typ Parameter
DrawAction (sender as object, width, height as word)


Mausunterstützung

Das Canvasobjekt unterstützt die Behandlung von Mausereignissen. Eine detaillierte Beschreibung der Arbeit mit der Maus finden Sie im Handbuch "Spezielle Themen", Kapitel 17.

Es ist möglich, innerhalb eines Maushandlers Grafiken oder Text auf den Bildschirm auszugeben. Dazu müssen Sie das Objekt explizit zum Screen machen. Häufig werden Sie außerdem die Maus grabben. Ein entsprechendes Beispiel ("Canvas Maus Demo") finden Sie im Ordner "Beispiel\Objekte\Grafik".

Beachten Sie aber, dass das Canvas-Objekt die Grafik- und Textausgaben nicht abspeichert! Sie werden nicht wieder gezeichnet, wenn das Objekt sich selbst neu darstellt.

Der gepufferte Modus

Im gepufferten Modus speichert das Objekt die darzustellende Grafik zwischen. Dadurch muss nicht jedes Mal der OnDraw-Handler gerufen werden, wenn sich das Objekt neu auf dem Bildschirm darstellen muss. Um den gepufferten Modus zu aktivieren verwenden Sie die Instancevariable buffered. Sie müssen dem Objekt auch mitteilen, wie groß die zu speichernde Datenmenge ungefähr (!) ist. Dazu verwenden Sie die die Instancevariable bufferedDataSize.

Es wird empfohlen, den gepufferten Modus zu verwenden.

Normaler Modus (buffered = FALSE):
Jedes Mal, wenn sich das Objekt auf dem Bildschirm neu darstellen muss, wird der BASIC OnDraw Handler gerufen. Das ist der Standardmodus. Für viele, insbesondere einfache Anwendungen ist er ausreichend.

Gepufferter Modus (buffered = TRUE)
Wenn sich das Objekt auf dem Bildschirm neu darstellen muss, wird die zwischengespeicherte Grafik dargestellt. Der BASIC OnDraw Handler wird nicht gerufen.

Vorteile des gepufferten Modus

  • Deutlich schnellere Darstellung.

  • Darstellung auch dann, wenn das BASIC-Programm "beschäftigt" ist. Wenn Ihr Programm eine hohe "Hintergrundaktivität" hat, z.B. bei einem Spiel, sollten Sie unbedingt den gepufferten Modus verwenden.

Nachteile des gepufferten Modus

  • Die Grafik kann sich Größenänderungen des Objekts nicht anpassen. Verkleinert sich das Objekt wird möglicherweise "über den Rand" gezeichnet.

Einschalten des gepufferten Modus
Setzen Sie die Instancevariable buffered auf TRUE. Das Objekt fordert Speicher zum Zwischenspeichern der Grafikbefehle an. Dann wird der OnDraw Handler gerufen. Die Grafikausgaben gehen aber nicht nur auf den Schirm, sondern werden parallel dazu vom Objekt "mitgeschnitten".

Sie können die Variablen buffered und bufferedDataSize auch schon im UI-Code setzen. Dann wird die gepufferte Grafik gleich beim Programmstart aufgebaut.

Ausschalten des gepufferten Modus
Setzen Sie die Instancevariable buffered auf FALSE. Das Objekt gibt den angeforderten Speicher frei. Anschließend wird der OnDraw Handler gerufen um das Objekt neu darzustellen.


Verwenden des OnDraw Handlers

Der OnDraw-Handler übernimmt die Darstellung der vom Objekt angezeigten Grafik. Das gilt sowohl für den normalen als auch für den gepufferten Modus, im gepufferten Modus wird der OnDraw-Handler genau einmal gerufen.

Während der OnDraw Handler läuft, wird das Canvas Objekt zum Screen, das heißt, alle Grafikausgaben gehen über dieses Objekt direkt auf den Bildschirm. Sie können alle Grafikbefehle verwenden, Farben ändern, Texte ausgeben usw., selbst Manipulationen des Koordinatensystems (siehe Kapitel 2.3.3) sind möglich. Falls ein globaler Screen gesetzt ist (siehe Kapitel 2.3) wird dessen Status vorher gesichert und anschließend wieder hergestellt, so dass es keine gegenseitige Beeinflussung geben kann. Mit einer Ausnahme: Alle Einstellungen rund um den Block-Grafik-Modus (siehe Handbuch "Spezielle Themen", Kapitel 2.5) sind immer global. Ändern Sie hier innerhalb eines OnDraw Handlers etwas (z.B. durch Laden eines anderen Zeichensatzes) wirkt sich das auf alle anderen Teile des Programms aus.

Beispiel UI Code:

Canvas DemoCanvas
  fixedsize = 300, 200
  OnDraw = DemoDraw
END OBJECT


Beispiel Handler:
DRAWACTION DemoDraw
  Paper 203
  CLS
  graphic.linewidth = 5
  Circle 150, 100,50, LIGHT_BLUE
  Print atxy 110,100;"Hallo"
END ACTION
Das Canvasobjekt führt ein automatisches Clipping aus, d.h. die Grafikteile, die über den Rand des Objekts ragen, werden nicht gezeichnet.

Sie können die aktuelle Größe des Zeichenbereichs ermitteln, indem Sie die Systemvariablen MaxX und MaxY abfragen. Da ist insbesondere dann hilfreich, wenn das Objekt seine Größe verändern kann, z.B. wenn die Hints ExpandWidth und ExpandHeight gesetzt sind.

Beispiel UI:

Canvas DemoCanvas
  initialSize = 150, 150
  OnDraw = DrawCircleHandler
  ExpandWidth
  ExpandHeight
END OBJECT


Beispiel Code. Es entsteht ein Viertelkreis.

...

DRAWACTION DrawCircleHandler    
  FillEllipse 0, 0, 2*MaxX, 2*MaxY, LIGHT_BLUE
END ACTION


Beschreibung der Instancevariablen

OnDraw

Die Instance-Variable OnDraw enthält den Namen des Handlers, der die Grafik zeichnen soll. Dieser muss als DrawAction vereinbart sein. Der Wert wird üblicherweise im UI-Code gesetzt.
Syntax UI-Code: OnDraw = <Handler> 
     Schreiben: <obj>.OnDraw = <Handler>

Bei Bedarf kann der OnDraw-Handler auch zur Laufzeit (im BASIC-Code) gesetzt werden. In diesem Fall stellt sich das Objekt automatisch neu dar.

Hinweis: Der neue OnDraw Handler wird erst ausgeführt nachdem der Handler, der die Zuweisung ausgeführt hat beendet ist!

defaultColor

Die Instance-Variable defaultColor enthält die Farben, die beim Aufruf des OnDraw Handlers eingestellt werden. Dabei setzt R-BASIC die Farben folgendermaßen:
               Hintergrundfarbe: bg
Text-, Linien- und Flächenfarbe: fg
Das ist prinzipiell so, als würde automatisch die Anweisung "COLOR fg, bg" ausgeführt, kostet aber deutlich weniger Zeit.
Syntax UI-Code: defaultColor = fg, bg  
            fg: Vordergrund (foreground)
            bg: Hintergrund (background)
                fg und bg müssen Indexfarben sein.
                RGB-Farben sind nicht zulässig.
         Lesen: <numVar> = <obj>.defaultColor (0)  ' fg
                <numVar> = <obj>.defaultColor (1)  ' bg
     Schreiben: <obj>.defaultColor = fg, bg 

Canvas Objekte ohne die Anweisung defaultColor verwenden die Farben "schwarz auf weiß".

buffered

Die Instancevariable buffered legt fest, ob das Canvasobjekt die anzuzeigende Grafik zwischenspeichert (buffered = TRUE, "gepufferter" Modus) oder nicht (buffered = FALSE, normaler Modus). FALSE ist der Defaultwert.
Wenn Sie den gepufferten Modus aktivieren sollten Sie ebenfalls die Instancevariable bufferedDataSize (siehe unten) im Blick haben.
Syntax UI-Code: buffered = TRUE
     Schreiben: <obj>.buffered = TRUE | FALSE
         Lesen: <numVar> = <obj>.buffered 

Ändern Sie den Wert der Instancevariablen buffered von FALSE auf TRUE oder von TRUE auf FALSE, so ruft das Objekt seinen OnDraw-Handler und stellt sich neu auf dem Bildschirm dar.

bufferedDataSize

Im gepufferten Modus fordert das Objekt Speicher (in einer Datei) an, um die darzustellende Grafik zu speichern. BufferedDataSize enthält die Information, wie groß der benötigte Speicher ungefähr (!) ist. Der Wert ist nicht kritisch. Wenn Sie hier einen falschen Wert angeben, passiert im Allgemeinen nichts.
Syntax UI-Code: bufferedDataSize = <Wert> 
     Schreiben: <obj>.bufferedDataSize = <Wert> 
         Lesen: <numVar> = <obj>.bufferedDataSize 
        <Wert>: numerische Konstante, siehe aus der Tabelle unten

Der Defaultwert für bufferedDataSize ist DS_TINY. Das ist ein sinnvoller Wert, wenn Sie nur Grafikbefehle verwenden und keine Bitmapgrafiken ausgeben. Die folgende Tabelle enthält die zulässigen Werte:

Konstante Wert Zu erwartende Datenmenge
DS_TINY 0 nicht mehr als 10 .. 20 kByte
DS_SMALL 1 nicht mehr als 50 .. 100 kByte
DS_MEDIUM 2 nicht mehr als 500 kByte ... 1 MB
DS_LARGE 3 nicht mehr als 5 MByte
DS_HUGE 4 möglicherweise mehr als 5 MByte

Beispiele, in welchen Situationen welche Datenmengen zu erwarten sind, finden Sie im Programmierhandbuch, Kapitel 2.8.5, bei der Beschreibung des Befehls StartRecordGS.

Dirty

Die Methode Dirty (engl: schmutzig) bewirkt, dass sich das Objekt neu darstellt, indem es seinen OnDraw Handler ruft. Verwenden Sie diese Methode wenn sich Daten, die zur Darstellung des Objekts relevant sind, geändert haben. Wenn das Objekt z.B. eine Pyramide darstellt und die Höhe der Pyramide hat sich geändert, dann müssen Sie die Dirty-Methode rufen, damit das Objekt die Pyramide mit der neuen Höhe zeichnet.
Syntax im BASIC Code: <obj>.Dirty

Die Dirty Methode arbeitet auch im gepufferten Modus. Das Objekt gibt die alte gepufferte Grafik automatisch frei und speichert die neue ab.

Tipps und Tricks

  • Per Default ist im OnDraw-Handler der LAYOUT Modus eingestellt. Das bedeutet, dass Textausgaben, die über den Rand des Ausgabefensters hinausgehen, keine neue Zeile eröffnen und beliebige, auch negative Cursor-Koordinaten erlaubt sind. Alternativ können Sie im OnDraw-Handler den PAGE Modus aktivieren, bei dem die Textausgabe auf das aktuelle Textfenster begrenzt wird.

    PAGE und LAYOUT Modus werden durch Ausgeben eines speziellen Steuerzeichens mit dem Print-Befehl aktiviert:

      PAGE Modus     Print "\17"   oder   Print Chr$(17)
      LAYOUT Modus   Print "\19"   oder   Print Chr$(19)
    
    In der KeyCodes Library sind entsprechende Konstanten definiert. Achtung! Der SCROLL-Modus (Print "\18") wird von Canvasobjekten nicht unterstützt und kann zu seltsamen Ergebnissen führen.

  • Canvasobjekte unterstützen die Zwischenablage nur im gepufferten Modus. Die Methoden ClpTestCopy und ClpTestPaste fragen daher als erstes ab, ob der gepufferte Modus aktiv ist. ClpCopy funktioniert im gepufferten Modus immer, ClpPaste akzeptiert Bitmaps und GStrings in der Zwischenablage.

    Beachten Sie, dass das Objekt seine Größe nach einer "Paste" Operation nicht an die neue Grafik anpasst. Unter Umständen wird die eingefügte Grafik über den Rand des Objekts hinaus gezeichnet.

    Im normalen Modus wird keine Clipboardarbeit unterstützt. ClpCopy und ClpPaste setzen die globale Variable clipboardError auf TRUE.

  • Vermeiden Sie die Verwendung des Befehls CLS im OnDraw-Handler. CLS ignoriert eventuelle Koordinatentransformationen und zeichnet ein Rechteck in der aktuellen Hintergrundfarbe. Diese Farbe ist meist nicht identisch mit der "Hintergrundfarbe" ihres GEOS-Systems. Im gepufferten Modus werden zudem vorher gezeichnete Objekte nicht entfernt, sondern nur überdeckt.

  • Ein Canvas-Objekt kann mit der Anweisung PrintObj gedruckt (also auf einen Drucker ausgegeben) werden. Diese Anweisung ist im Objekthandbuch, Kapitel 4.14.7 (Drucken spezieller Objekte) beschrieben. Das Canvas-Objekt muss dazu im gepufferten Modus arbeiten.

^

Weiter...