2.0 Grundlegende Konzepte

2.1.0 Objekte und Objekt-Bäume (Trees)

2.1.1 Überblick

2.1.2 Arbeit mit Objekten

2.1.3 Verwaltung von Objektblöcken (*)

2.1.4 Beeinflussung der Objektblöcke im UI-Code (*)

2.1.5 Anlegen und Vernichten von Objekten zur Laufzeit (*)

(*) Kapitel für Fortgeschrittene

^

2.1 Objekte und Objekt-Bäume (Trees)

2.1.1 Überblick

Objekte sind unter GEOS in sogenannten Bäumen (Trees) organisiert. Jedes Objekt hat genau ein Parent (Eltern) und kann kein, ein oder mehrere Children (Kinder) haben. Der Objekt-Tree eines Programms im 'klassischen' BASIC-Modus sieht wie folgt aus (vergleiche UI-Code im Anschnitt 1.1):

...

Die gelb hinterlegten Objekte werden dabei vom Primary-Objekt automatisch angelegt und erscheinen daher nicht im UI-Code. Das Parent des Primary-Objekts ist das Application-Objekt, seine Children sind das FileMenu und das Bitmap-Objekt. Aus der Sicht des FileMenu ist sein Parent-Objekt das Primary, die Children des FileMenu sind zwei Groups (Gruppen), die jeweils den BreakButton bzw. den ExitButton enthalten. Das DemoBitmap-Objekt ist kein direkter Teil des Trees, es ist das Content-Objekt des DemoView-Objekts (siehe Kapitel 4.9).

Der Objekttree eines Programms dient sowohl der Kommunikation der Objekte untereinander (was in R-BASIC meist intern stattfindet) als auch der Anordnung der Objekte auf dem Bildschirm. Children zeichnen sich immer in den Grenzen, die ihnen das Parent vorgibt. Außerdem legt das Parent-Objekt fest, ob die Children neben- oder untereinander angeordnet werden und wie sie sich den vorhandenen Platz aufteilen. Details dazu finden Sie im Kapitel über das Geometriemanagement.

R-BASIC unterstützt die Arbeit mit Objekt-Trees sehr ausführlich. Sie können Informationen über das Parent und die Children eines Objekts erhalten, Objekte aus dem Tree entfernen und an anderer Stelle einfügen.

GenericClass Tree und VisualClass Tree

In R-BASIC Programmen gibt es zwei Arten von Objekt-Trees: den GenericClass Tree und den VisualClass Tree. Gelegentlich wird auch der allgemeine Term 'UI-Tree' verwendet. Welcher Tree gemeint sein kann, ergibt sich dann aus dem Kontext.

Der GenericClass Tree (kurz: generic Tree) enthält die 'normalen' GEOS-Objekte, wie Primary, Listen, Text-Objekte aber auch z.B. Dialogboxen. Sie stammen alle von der GenericClass ab. GenericClass-Objekte können nur auf dem Bildschirm erscheinen, wenn von ihnen ein vollständiger Pfad zum Application-Objekt führt. Das bedeutet, dass das Objekt selbst, sein Parent, dessen Parent oder ein anderes 'übergeordnetes' (Parent-) Objekt letztlich mit dem Application-Objekt verbunden ist. Mit Objekten oder Objekt Trees, die nicht vollständig in den Tree eingebunden sind, kann man trotzdem arbeiten, d.h. man kann Instance-Variablen lesen und schreiben. Die veränderten Werte werden wirksam, sobald das Objekt vollständig in den Tree eingebunden ist und auf dem Bildschirm erscheint.

Der VisualClass Tree (kurz: visual Tree) enthält Objekte, von der VisualClass abstammen. Das Top-Objekt (oberstes Parent) ist ein VisContent oder BitmapConten-Objekt. Der Tree erschient auf den Bildschirm, sobald das Top-Objekt einem View-Objekt als 'content' (=Inhalt) zugewiesen wird. Das View managed dann wie der visual Tree dargestellt wird. Details dazu finden Sie im Abschnitt über View- und Content-Objekte (Kapitel 4.9) sowie im Kapitel über die VisualClass (Kapitel 5).

In vielen Fällen besteht der 'VisualClass Tree' ausschließlich aus dem VisContent bzw. BitmapContent-Objekt. Einfache BASIC-Programme haben oft gar keinen VisualClass Tree. Komplexe Programme können mehrere Visual Trees haben und machen ggf. ausführlich von der Möglichkeit, Objekte anzulegen, wieder zu vernichten und im Tree zu verschieben, gebrauch.

Achtung! Es ist illegal, den GenericClass Tree und den VisualClass Tree zu mischen, d.h. in den GenericClass Tree Objekte einzufügen, die von der VisualClass abstammen und umgekehrt. Die Verbindung passiert ausschließlich über die 'Content' Instance-Variable eines View-Objekts.

^

2.1.2 Arbeit mit Objekten

Die hier vorgestellten Möglichkeiten sind sowohl auf den GenericClass Tree als auch auf den VisualClass Tree anwendbar.

Instance-Variablen:

Variable Syntax im UI-Code Im BASIC-Code
Class$ -- nur lesen
Children Children = <objektListe> nur lesen
numChildren -- nur lesen
parent -- lesen, schreiben


Methoden

Syntax im BASIC-Code Aufgabe
<numVar> = <obj>.FindChild( <childObj> ) Child suchen


Routinen

Syntax im BASIC-Code Aufgabe
<stringVar> = ObjInfo$( <obj> ) interne Informationen anfordern


Class$

Class$ enthält den Namen der Objektklasse im Klartext, z.B. 'MEMO', oder 'DYNMAIC_LIST'. Class$ kann nur gelesen werden. Ist das Objekt kein gültiges BASIC-Objekt, z.B. ein Null-Objekt, liefert Class$ einen leeren String.
Syntax Lesen: <stringVar> = <obj>.Class$

 

Children

Children legt im UI-Code fest, dass die aufgezählten Objekte Children des aktuellen Objekts sind.


Syntax im UI-Code: Children = <objektListe>

 

Beispiel:

Primary MyPrimary
  Children = InfoMenu, MainGroup, BitmapArea
END Object

Die hinter Children auftauchenden Objekte müssen an anderer Stelle im UI-Code vereinbart sein. Jedes Objekt darf nur in maximal einer Children-Liste auftauchen. Ein Objekt nirgends als Child zu spezifizieren ist ok.

Die Anzahl der Objekte in einer einzigen Childrenliste ist auf 25 begrenzt. Wenn Sie mehr Children spezifizieren wollen können Sie mehrere Childrenanweisungen für ein Objekt verwenden.

Beispiel:

Group MyBigGroup
  Children = Button1, Group1
  Children = Button2, Group2
END Object

Beachten Sie, dass der Compiler die Children-Anweisungen nicht sofort ausführt, sondern sie zunächst auf eine Stapelspeicher (Stack) legt um sie am Ende des UI Compilevorgangs in umgekehrter Reihenfolge auszuführen. Die beiden Children-Anweisungen im obigen Beispiel sind also identisch mit:

Group MyBigGroup
  Children = Button2, Group2, Button1, Group1
END Object
Im BASIC-Code kann lesend auf die Child-Objekte eines Objekts zugegriffen verwenden:
Syntax Lesen: <objVar> = <obj>.Children ( index )
              index gibt die Nummer des Child-Objekts an
              Wertebereich 0 .. numChildern - 1

 
Beispiel Basic-Code:
DIM obj, obj2 AS OBJECT
  obj = MyPrimay.Children(0)	! erstes Child-Objekt lesen
  Print obj.Caption$

numChildren

NumChildren kann nur im BASIC-Code auftreten und kann nur gelesen werden. Es liefert die Anzahl der direkten Children des Objekts. Sollten die Child-Objekte eigenen Children haben, werden diese nicht mitgezählt.


Syntax Lesen: <numVar> = <obj>.numChildren

Beispiel:

DIM n AS WORD
  n = MyPrimary.numChildren
  Print "MyPrimary hat";n;"Children"

parent

Parent kann nur im BASIC-Code auftreten. Es kann gelesen und geschrieben werden. Im UI-Code können sie das Parent nicht direkt setzen, sondern müssen über die Children-Liste gehen.

Lesen: Parent liefert das Parent-Objekt. Sollte das Objekt kein Parent haben, wird ein Null-Objekt zurückgegeben (analog der NullObj() Funktion).


Syntax Lesen: <objVar> = <obj>.parent

 
Beispiel:
DIM obj AS OBJECT
  obj = MyView.parent
  IF obj = NullObj() THEN
    Print "MyView hat kein Parent"
  ELSE
    Print "'Caption$ = "; obj.Caption$
  END IF
Schreiben: Parent weist einem Objekt ein neues Parent-Objekt zu. Damit wird das Objekt im UI-Tree verschoben. R-BASIC handelt alle dafür notwendigen Schritte. Sie können auch ein Null-Parent zuweisen (mit der Funktion NullObj() ). Das Objekt wird versteckt, ist aber bereit an gleicher oder anderer Stelle wieder eingefügt zu werden.
Syntax Schreiben: <obj>.parent = <obj2> , index
                  index: Position (= neue ChildNr, beginnend bei Null),
                  an der das Objekt eingefügt werden soll.
                  0: als erstes Child, 1: als 2. Child usw.
                  Sonderfall: -1 als letztes Child

 
Beispiel: Ausgangssituation im UI-Code
Group MyGroup1
  Children = MyButton1, MyButton2, MyButton3, MyButton4
END Object

Group MyGroup2
  Children = MyButton5
END Object

Beispiele BASIC-Code:

  ! Button5 nach Group1 verschieben, als erstes Child
    MyButton5.Parent = MyGroup1, 0

  ! Button5 nach Group1 verschieben, als vorletztes Child
  ! Die Reihenfolge ist dann
  ! MyButton1, MyButton2, MyButton3, MyButton5, MyButton4
    MyButton5.Parent = MyGroup1, 3

  ! Button5 aus dem Tree entfernen
    MyButton5.Parent = NullObj() ,  0

  ! Button5 wieder zu Grpup2 hinzufügen, als letztes Child
    MyButton5.Parent = MyGroup2, -1
Beachten Sie, dass sich die Child-Nummern der Objekte, die sich hinter dem eingefügten Objekt befinden, verändern.

FindChild

Die Methode FindChild untersucht, ob zwei Objekte im Child-Parent Verhältnis zueinander stehen.


      Syntax: <numVar> = <obj>.FindChild( <childObj> )
       <obj>: Variable oder Ausdruck vom Typ OBJECT
  <childObj>: Variable oder Ausdruck vom Typ OBJECT
              Es wird geprüft ob <childObj> ein Child von <obj> ist.
Rückgabewert:
              0 .. N <childObj> ist ein Child von <obj>
              Der Wert ist die Childnummer, die Zählung beginnt bei Null.
              - 1 <childObj> ist kein Child von <obj>

 

ObjInfo$

Die Stringfunktion ObjInfo$ liefert interne Informationen über das Objekt. Sie können die Funktion zur Fehersuche in Objekt-Trees verwenden. Der String könnte z.B. so aussehen:

ObjReferenz=18:34, Typ=3 (BUTTON) * [Gen]
Die ObjektReferenz identifiziert ein Objekt eindeutig. Die erste Zahl beschreibt den Objektblock, in der sich das Objekt befindet.
Der Typ beschreibt die Objekt-Klasse eindeutig. Zusätzlich ist der Klassen-Name noch im Klartext angegeben.
Syntax: <stringVar> = ObjInfo$ ( <obj> )
 <obj>: Variable oder Ausdruck vom Typ OBJECT


^

2.1.3 Verwaltung von Objektblöcken

Diese Kapitel richtet sich an fortgeschrittene Programmierer.

R-BASIC ist daraufhin optimiert, die Verwaltung der Objektblöcke weitgehend automatisch zu erledigen. Dieses Kapitel enthält grundlegende und Hintergrundinformationen für den Fall, dass Sie ein Problem mit der Objektblockgröße haben (Kapitel 2.1.4) oder dass Sie Objekte zur Laufzeit des Programms anlegen wollen (Kapitel 2.1.5).

BASIC-Anweisungen

Syntax im BASIC-Code Aufgabe
<handleVar> = GetObjBlockHandle(<obj>) Handle eines Objektblocks lesen
<numVar> = GetObjBlockSize( <handle> ) Größe eines Objektblocks lesen
<handleVar> = CreateObjBlock ( ) Neuen Objektblock anlegen
DestroyObjBlock <handleVar> Objektblock löschen

GEOS und damit R-BASIC verwaltet den Speicher in 'Blöcken' von einigen Kilobytes Größe. Das gilt auch für Objekte. Die Instance-Daten (persönliche Daten) eines Objekts nehmen einige 10 bis einige 100 Byte ein. Es werden daher immer mehrere Objekte gemeinsam in einem Speicherblock abgelegt. Einen solchen Speicherblock nennt man 'Objektblock'. Jedes Mal, wenn auf die Instance-Daten eines Objekts zugegriffen werden muss, z.B. weil das Objekt sich auf dem Schirm darstellt oder weil Sie es angeklickt haben und es auf den Mausklick reagiert, wird der gesamte Objektblock in den Hauptspeicher geladen.

Die Aufteilung der Objekte auf Objektblöcke ist prinzipiell völlig unabhängig von der Verbindung der Objekte im generic Tree oder im visual Tree. Auf modernen Rechnern ist der geringe Performanceverlust, der auftritt, wenn man Objekte 'Kreuz und Quer' über viele Objektblocks verlinkt, zu vernachlässigen. Trotzdem ist es schon aus Gründen der Übersichtlichkeit ratsam, zusammengehörende Objekte, z.B. alle Objekte einer Dialogbox, im UI-Code zusammenhängend zu deklarieren. R-BASIC platziert sie dann automatisch im gleichen Objektblock.

GetObjBlockHandle


     Syntax: <handleVar> = GetObjBlockHandle( <obj> )
      <obj>: Variable oder Ausdruck vom Typ OBJECT
<handleVar>: Variable vom Typ HANDLE

Um unter R-BASIC mit Objektblöcken arbeiten zu können, benötigen Sie ein Handle auf den Objektblock. Die Funktion GetObjBlockHandle() liefert das Handle des Objektblocks, in dem sich das übergebene Objekt befindet.

GetObjBlockSize


Syntax: <numVar> = GetObjBlockSize( <han> )
 <han>: Variable oder Ausdruck vom Typ HANDLE
        Es muss das Handle eines Objektblocks sein.

Die Funktion GetObjBlockSize() liefert die aktuelle Größe des Objektblocks, dessen Handle der Funktion übergeben wurde.

Der GEOS Speichermanager ist auf Blockgrößen von 6 kByte bis 8 kByte optimiert. Natürlich kann er auch mit Blöcken von wenigen Bytes umgehen, z.B. mit Objektblöcken, die nur ein einziges Objekt enthalten - das ist jedoch nicht effizient und kostet unnötig Systemhandles (jeder Block benötigt sein eigenes Handle). Werden die Blöcke hingegen zu groß kann es länger dauern bis der Speichermanager einen Platz im Hauptspeicher für diesen Block gefunden hat. Unter Umständen muss er dazu andere Blöcke, die gerade nicht benutzt werden auf die Festplatte auslagern. Das kann dauern.

Blockgrößen von 10 oder 16 Kilobytes sind dabei noch kein echtes Problem, bei Blockgrößen von z.B. 40 kByte oder mehr kann es jedoch zu den gefürchteten 'Hauptspeicher voll' Meldungen kommen.

Um diesbezügliche Probleme zu vermeiden geht R-BASIC beim Compilieren des UI-Codes folgendermaßen vor:

Vor dem Anlegen eines neuen Objekts prüft es die Größe des aktuell verwendeten Objektblocks. Sollte dieser bereits mehr als 6 kByte groß sein, so wird vor dem Anlegen des neuen Objekts ein weiterer Objektblock angelegt. Das neue und alle folgenden Objekte werden dann in dem neuen Objektblock gespeichert. Dabei berücksichtigt R-BASIC, dass einige Objekte zur Laufzeit weiteren Speicher benötigen oder benötigen könnten. Beispielsweise speichern drei der vier Text-Objekte (Memo, InputLine und VisText) ihren Text in ihrem eigenen Objektblock. Die Instance-Variable maxLen gibt an, wie viele Zeichen der Text maximal enthalten kann. R-BASIC berücksichtigt das bei der Berechnung der Objektblockgröße. Deswegen sind Objektblocks, die Text-Objekte enthalten, anfangs häufig kleiner als 6 kByte. Ähnliches gilt für DynamicList-Objekte. Diese erzeugen zur Laufzeit ihre eigenen Children. R-BASIC berücksichtigt das pauschal mit 1,5 kByte, was in den meisten Fällen völlig ausreicht.

CreateObjBlock


Syntax: <handleVar> = CreateObjBlock ( )

Die Funktion CreateObjBlock( ) legt einen neuen, leeren Objektblock an. Sie liefert das Handle des Objektblocks zurück. Dieses benötigen Sie, wenn Sie neue Objekte in diesem Block anlegen wollen (CreateObject(), siehe Kapitel 2.1.5) oder den Objektblock später wieder vernichten wollen.

DestroyObjBlock


Syntax: DestroyObjBlock <han>
 <han>: Variable oder Ausdruck vom Typ HANDLE
        Es muss das Handle eines Objektblocks sein.

Die Anweisung DestroyObjBlock vernichtet einen Objektblock und gibt den damit verbundenen Speicher wieder frei.

Wichtig:

  • Der Objektblock darf keine Objekte mehr enthalten. Verwenden Sie dazu DestroyObject() (siehe Kapitel 2.1.5).

  • Es ist dringend davon abzuraten Objektblöcke zu vernichten, die vom UI-Compiler erzeugt wurden. Vernichten Sie nur Objektblöcke, die mit CreateObjBlock() angelegt wurden.

^

2.1.4 Beeinflussung der Objektblöcke im UI-Code

Diese Kapitel richtet sich an fortgeschrittene Programmierer.

R-BASIC kümmert sich um Objektblöcke und die damit zusammenhängenden Dinge weitgehend selbständig. Die meisten Programmierer werden daher niemals selbst mit der Verwaltung von Objektblöcken zu tun haben.

Es gibt jedoch einige wenige Situationen die das direkte Eingreifen des Programmierers erfordern. Das sind konkret:

  • DynamicList Objekte, die grafische Elemente anzeigen.

  • Zuweisungen von grafischen Captions zur Laufzeit

  • Textobjekte mit sehr großen Texten
Diese sowie die dafür nötigen Hintergrundinformationen sind hier beschrieben.

UI-Anweisungen

Syntax im UI-Code Aufgabe
ForceNewObjBlock Einen neuen Objektblock anfordern

Nach dem Compilieren erhalten Sie eine Tabelle, die wie folgt aussehen könnte. Die Spalte 'Ab Zeile' enthält die Zeile im UI-Code, in der ein neuer Objektblock angelegt wurde. Daraus können Sie ermitteln welche Objekte in welchem Objektblock gespeichert sind. 'Größe' enthält die anfängliche Größe des Objektblocks in Byte. 'Objekte' enthält die Anzahl der im Objektblock gespeicherten Objekte. Beachten Sie, dass das Application-Objekt in einen eigenen Objektblock compiliert wird.

Objektblöcke compiliert: 3
Ab Zeile     Größe      Objekte
   36         4280         33
  196         1592          5
Interner Objektblock: Application

Wie bereits oben erwähnt brauchen Sie hier im Normalfall nicht einzugreifen, insbesondere dann nicht, wenn Ihnen die Blockgrößen sehr klein erscheinen. R-BASIC wählt einen guten Kompromiss auf anfänglicher Blockgröße und dem möglichen Blockwachstum zur Laufzeit. Ein nachträgliches Verschieben eines Objekts in einen anderen Block ist leider nicht möglich.

Es gibt jedoch einige Situationen, die R-BASIC nicht vorhersehen kann. Diese sind im Folgenden erklärt. Sie beziehen sich alle auf Veränderungen der Objekte zur Laufzeit. Als Richtwert kann gelten, dass Objektblöcke zur Laufzeit nicht größer als 14 bis 16 kByte werden sollten. Optimal sind weniger al 10 kByte. Wie Sie das herausbekommen ist weiter unten erklärt. Bei mehr als 20 kByte Blockgröße ist es dringend zu empfehlen gegenzusteuern.

Fall 1: DynamicList Objekte

Ein häufiger Fall, in dem die Blockgröße kritisch anwachsen kann, sind dynamische Listen, die grafische Elemente anzeigen. Dynamische Listen erzeugen Ihre Children zur Laufzeit selbst. Dafür wird Platz im Objektblock benötigt. Es zählen dabei nur die gleichzeitig sichtbaren Listeneinträge. R-BASIC unterstellt der Liste bei der Berechnung der Objektblockgröße einen Platzbedarf von 2 kByte, das entspricht ca. 25 gleichzeitig angezeigten Listeneinträgen mit je 20 Zeichen Text-Caption. Aber auch ein realer Bedarf von 4 oder 6 kByte sind kein Problem - falls man nicht mehrere solcher Listen im gleichen Objektblock hat.

Ein echtes Problem können aber viele Listeneinträge mit einer Grafik sein (Anweisung ItemGString). In diesem Fall ist es eine gute Idee das DynamicList-Objekt ein einem eigenen Objektblock, nur für dieses Objekt, unterzubringen. Dazu verwenden Sie die unten beschriebene Anweisung ForceNewObjBlock.

Fall 2: Grafische Captions

Auch die 'Objekt-Beschriftung' (Caption$ oder grafische Captions) wird im gleichen Objektblock gespeichert wie das Objekt selbst. Text-Captions (Caption$) stellen dabei niemals ein Problem dar, da sie nur wenige Bytes umfassen. Wenn sie einen Text durch einen anderen ersetzen ändert sich die Objektblockgröße nur um wenige Bytes, ggf. wird sie sogar kleiner.

Haben Sie jedoch im UI-Code eine Text-Caption (oder gar keine) angegeben und weisen einem Objekt zur Laufzeit eine Grafik als Caption zu (Anweisungen CaptionIcon, CaptionPicture, CaptionImage und CaptionGString), so wird auch diese im Objektblock des Objekts gespeichert. Wenn Sie dies bei mehreren Objekten tun kann das den Objektblock zu stark vergrößern. Beispielsweise nimmt ein Icon der Bitmap-Größe 48x30 Pixel im ungünstigsten Fall (TrueColor, unkomprimiert) ca. 4 kByte ein, bei 8 Bit unkomprimiert sind es immer noch 1,4 kByte. Weitere Informationen dazu finden Sie im Kapitel 3.1 (Caption: Die Objekt-Beschriftung).

Auch hier gilt: Weisen Sie die Grafik bereits im UI-Code zu, erkennt R-BASIC die Größe und verteilt die fraglichen Objekte auf verschiede Objektblöcke.

Fall 3: Textobjekte

Der hier beschriebene Fall ist kommt eher selten vor, aber man sollte ihn kennen. Wie bereits oben erwähnt speichern Textobjekte (außer LargeText) ihren Text in ihrem eigenen Objektblock. Wie groß dieser Text werden kann hängt von der Instance-Variablen maxLen des Textobjektes ab. Der Standardwert für maxLen ist 1024.

Wenn Sie zur Laufzeit den Wert für maxLen deutlich vergrößern (gegenüber dem Wert, der beim Compilieren festgelegt wurde) und das auch ausnutzen (d.h. so viel Text dort speichern) wird der Objektblock größer als vom Compiler angenommen. Machen Sie das für viele Textobjekte aus dem gleichen Block kann es zu einem Problem werden.

Es macht daher Sinn bei Textobjekten den Wert für maxLen im UI-Code so klein wie möglich, aber auch so groß wie nötig zu wählen. Dann löst R-BASIC das Problem für Sie, indem es die Objekte auf mehrere Blöcke verteilt. Eine Verkleinerung des Wertes für maxLen zur Laufzeit stellt dagegen niemals ein Problem dar.

Wie erkennt man, ob es ein Problem gibt?

Um Informationen über einen Objektblock zu erhalten muss man zuerst das 'Handle' des Blocks ermitteln. Die Funktion GetObjBlockHandle() liefert das Handle des Objektblocks, in dem sich das übergebene Objekt befindet. Danach kann man mit der Funktion GetObjBlockSize() die aktuell gültige Größe des Objektblocks ermitteln.

Wenn Sie den Verdacht haben, dass ein Objektblock zu groß geworden ist, rufen Sie diese beiden Routinen für ein Objekt aus diesem Block, wie im folgenden Beispiel gezeigt:

DIM han AS HANDLE
DIM size
  han = GetObjBlockHandle(MyDanamicList)
  size = GetObjBlockSize (han)
  MsgBox Str$(size)

Dabei ist es normal, wenn die Größe eines Objektblocks zur Laufzeit etwas größer ist, als in der Tabelle vom Compiler angegeben. GEOS arbeitet mit den Objektblocks. Z.B. fügt es bei einigen Objekten je nach Bedarf eigene (interne) Instance-Werte hinzu oder löscht diese wieder. Beim Löschen wird der Speicher zwar als 'frei' markiert, der Block aber nicht unbedingt sofort verkleinert. Daher ist es auch normal, wenn die Größe vom Mal zu unterschiedlich ist, auch wenn Sie 'gar nichts gemacht' haben. Sie können jedoch gut erkennen, ob der Objektblock eine kritische Größe (mehr als 16 bis 20 kByte) erreicht hat oder nicht.

Was kann man tun?

Der einzige Weg, Einfluss auf die Verteilung der Objekte auf die Objektblöcke zu nehmen, ist, dem UI-Compiler anzuweisen, einen neuen Objektblock anzulegen.

ForceNewObjBlock


Syntax im UI-Code: ForceNewObjBlock

Platzieren Sie den UI-Befehl ForceNewObjBlock (Erzwinge neuen Objektblock) je nach Situation vor oder nach dem kritischen Objekt. Es ist auch möglich die fraglichen Objekte (oder das einzelne Objekt) in zwei ForceNewObjBlock-Anweisungen einzuschachteln.
ForceNewObjBlock

DynamicList MyBigList
  ....
END Object

ForceNewObjBlock
Findet der UI-Compiler eine ForceNewObjBlock-Anweisung schließt er den aktuell verwendeten Objektblock und legt für die folgenden Objekt einen neuen an.

Tipp: Legen Sie die fraglichen Objekte ans Ende aller UI-Anweisungen, dann werden die davor befindlichen Objektblöcke nicht unnötig eingekürzt.

^

2.1.5 Anlegen und Vernichten von Objekten zur Laufzeit

Diese Kapitel richtet sich an fortgeschrittene Programmierer.

Üblicher Weise legt R-BASIC die im UI-Code deklarierten Objekte an, wenn das Programm compiliert wird. R-BASIC bietet Ihnen aber auch die Möglichkeit, weitere Objekte zur Laufzeit anzulegen und wieder zu vernichten. Für GenericClass Objekte (z.B. Button oder Menu) wird diese Möglichkeit eher selten genutzt. Einige komplexe Programme, wie z.B. der Grafikbetrachter Gonzo, nutzen aber die gebotenen Möglichkeiten für VisualClass Objekte sehr intensiv. Gonzo legt für jede Grafikdatei, die es findet, ein eigenes Objekt an. Dieses Kapitel beschreibt, wie man Objekte zur Laufzeit anlegt, damit arbeitet, wieder vernichtet und was es dabei zu beachten gilt.

Beachten Sie, dass die VisContent Objekte über eingebaute Methoden verfügen, die das Anlegen und Vernichten von VisObj-Objekten stark vereinfachen.

BASIC-Anweisungen

Syntax im BASIC-Code Aufgabe
<objVar> = CreateObject ( <han>, <objClass>) Neues Objekt erzeugen
DestroyObject <obj> Objekt vernichten


Wie im Kapitel 2.1.3 beschrieben verwaltet GEOS alle Objekte in Objektblöcken. Um ein Objekt zur Laufzeit anzulegen müssen Sie außer der Klasse des Objekts auch den Objektblock spezifizieren, in dem das Objekt angelegt werden soll. Das typische Vorgehen beim Arbeiten mit selbst angelegten Objekten ist im Folgenden beschrieben. Es unterscheidet sich für GenericClass-Objekte und VisualClass-Objekte nicht.

  1. Erzeugen Sie einen neuen Objektblock mit CreateObjBlock().

  2. Legen Sie die neuen Objekte mit CreateObject() an. Initialisieren Sie die Instancevariablen und binden Sie die Objekte in den Tree ein.

  3. Arbeiten Sie mit den Objekten.

  4. Nachdem Sie die Objekte nicht mehr brauchen, sollen Sie sie mit DestroyObject() vernichten. Dadurch wird der Speicher im zugehörigen Objektblock freigegeben.

  5. Am Schluss, nachdem alle Objekte im Objektblock vernichtet wurden, sollten Sie den Objektblock mit DestroyObjBlock() vernichten.

Die Befehle CreateObjBlock() und DestroyObjBlock sind im Kapitel 2.1.3 beschrieben.

CreateObject


    Syntax: <objVar> = CreateObject (<han>, <objClass>)
     <han>: Handle eines Objektblocks
<objClass>: Bezeichnung einer Objektklasse

Die Funktion CreateObject() legt ein neues Objekt in dem Objektblock an, dessen Handle der Funktion übergeben wurde. Als Objektklasse (dem 'Typ' des Objekts) sind alle R-BASIC Klassen, außer Application, zulässig.

Beispiele:

DIM  o, p, q AS OBJECT

    o = CreateObject (han, Button)
    p = CreateObject (han, Dialog)
    q = CreateObject (han, Menu)
Um das Objekt nutzen zu können müssen Sie noch seine Instance-Variablen initialisieren und das Objekt in den Tree einbinden.

Ausführliches Beispiel: siehe unten

Hinweise:

  • Je nach Klasse benötigt jedes Objekt einige 10 bis einige 100 Byte. Objektblöcke sollten nicht zu groß werden. Die Idealgröße liegt zwischen 6 kByte und 8 kByte. Verwenden Sie im Zweifelsfall die Funktion GetObjBlockSize() um die aktuelle Größe des Objektblocks zu ermitteln. Details dazu sind im Kapitel 2.1.3 beschrieben.

  • Auch wenn es möglich ist: Sie sollten keine Objekte in den Objektblocks anlegen, die vom Compiler erzeugt wurden.

DestroyObject


Syntax: DestroyObject <obj>
 <obj>: Variable oder Ausdruck vom Typ OBJECT
        Das Objekt wird vernichtet.

Die Anweisung DestroyObject vernichtet ein Objekt. Damit ein Objekt vernichtet werden kann darf es nicht mehr im Tree eingebunden oder auf andere Weise mit anderen Objekten verbunden sein. R-BASIC erzeugt einen Laufzeitfehler, wenn diese Bedingungen verletzt sind, um einen Absturz des Systems zu verhindern.

Hinweis:

  • Auch wenn es möglich ist: Sie sollten keine Objekte vernichten, die vom Compiler erzeugt wurden.

Beispiel: Anlegen eines Objekt-Trees

DIM h as HANDLE
DIM d, t, b as OBJECT

  h = CreateObjBlock()
  d = CreateObject(h, Dialog)
  d.Caption$ = "Neuer Dialog"
  d.Parent = DemoPrimary,1

  t = CreateObject (h, Memo)
  t.Caption$ = "Text eingeben"
  t.justifyCaption = J_TOP
  t.Parent = d, 0

  b = CreateObject(h, button)
  b.Caption$ = "Fertig"
  b.ActionHandler = TestAction
  b.Parent = d,1

Beispiel: Vernichten eines Objekt-Trees

BUTTONACTION TestAction
    Print "Button pressed!"
    Print t.text$

    b.Parent = NullObj(), 0
    DestroyObject b

    t.Parent = NullObj(), 0
    DestroyObject t

    d.Parent = NullObj(), 0
    DestroyObject d

    DestroyObjBlock h
END ACTION

^

Weiter...