19. Objekte individualisieren

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 in einer globalen Variablen speichern. Das ist aber nicht nur schlechter Stil sondern wird bei mehreren solchen Objekte auch schnell sehr unübersichtlich und damit fehleranfä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 Strukturvariable 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.

Fortgeschrittene Programmierer können in einigen 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.

PrivData

PrivData ist für alle Klassen definiert. Sie nimmt eine einzelne Strukturvariable (also maximal 3500 Bytes) auf. Diese Instancevariable 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. Verwenden Sie dazu die Funktion SIZEOF.

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

Lesen: <structVar> = <obj>.privData

<struct>: Strukturausdruck beliebigen Typs
size: Größe der Struktur
<structVar>: Strukturvariable des Typs, der beim Schreiben verwendet wurde.

Achtung! PrivData kann nicht im UI Code belegt werden! Wenn Sie wollen, dass privData am Programmstart mit vorgegebenen Werten belegt wird, müssen Sie das im OnStartup Handler tun.

Beispiel:

Ein Canvas-Objekt soll einen Kreis oder ein Quadrat in einer vorgegebenen Farbe zeichnen. Wir benötigen:

- einen Strukturtyp, der die Informationen enthält,
- eine Routine, die die Werte setzt,
- ein Canvas-Objekt,
- einen OnDraw Handler für das Canvas Objekt,
- einen OnStartup Handler für das Application Objekt.
Der Strukturtyp sei folgendermaßen definiert:
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
  DemoCanvas.privData = pd, SIZEOF(pd)
  DemoCanvas.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 DemoCanvas
  OnDraw = DrawFigure
  fixedSize = 70, 70
End Object

Unser Application-Objket benötigt einen OnStartup Handler.
Application DemoApplication
  Children = DemoPrimary
  OnStartup = AppStartup
End OBJECT

Schließlich benötigen wir noch den OnDraw-Handler, der die privData-Werte ausliest und verwendet, sowie den OnStartup Handler für das Application-Objekt.
DRAWACTION DrawFigure
DIM priv as ImgData
  priv = sender.privData
  INK priv.color
  IF priv.isCircle THEN
    FillEllipse 10, 10, 60, 60
  ELSE
    FillRect 10, 10, 60, 60
  END IF
End Action
SYSTEMACTION AppStartup
  SetCanvasToCircle(LIGHT_RED)
END ACTION

CustomHandler

CustomHandler 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:

Tabelle

CustomApply

Die 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

BUTTON 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
DIM i
  IF actionData < 0 THEN i = RED : ELSE i = BLUE
  Print Ink i;"DATA = ";actionData
End Action

Wenn der Nutzer den Button drückt erscheint folgendes:
Text 1
Text 2
Text 3
DATA = 1
DATA =-7

^

Weiter...