5.4 VisContent

5.4.1 Grundlegende Fähigkeiten

5.4.2 View-Content Konfiguration

5.4.2.1 Wenn das Content eine feste Größe hat

5.4.2.2 Wenn das Content eine variable Größe hat

5.4.3 Anlegen und Vernichten von Objekten

... Objekte der Klasse VisContent dienen primär dazu, Grafiken in einem skalierbaren und scrollbaren View auszugeben. Sie können außerdem auf Tastatur- und Mauseingaben reagieren. Das VisContent-Objekt muss nur die Grafik bereitstellen, das View-Objekt kümmert sich um den darzustellenden Bereich, Scrolling und Zoom.

Dazu kann das VisContent-Objekt selbst Grafik ausgeben, oder es verwendet Children (der Klasse VisObj), die ihrerseits Grafik ausgeben und auf Tastatur und Maus reagieren können. Es ist die Entscheidung des Programmierers, welcher Weg benutzt wird. Es ist auch möglich, dass das VisContent, wie im Bild gezeigt, eine Hintergrundgrafik ausgibt, auf die dann die VisObj-Objekte gezeichnet werden.

Abstammung:

...

Da VisContent Objekte von der VisualClass abstammen, kommen Sie nicht in den generic Tree des Programms. Stattdessen werden sie über die Instance-Variable "Content" eines Views mit dem View verbunden. Das View muss aber in den generic Tree des Programms eingebunden werden.

Spezielle Instancevariablen:

Variable Syntax im UI-Code Im BASIC-Code
contentAttrs contentAttrs = toSet, toClear lesen, schreiben
holdsLargeText holdsLargeText = TRUE lesen, schreiben

Methoden:

Methode Aufgabe
CreateVisObject Neues VisObj-Objekt anlegen
DestroyVisObject Mit CreateVisObject VisObj-Objekt vernichten


^

5.4.1 Grundlegende Fähigkeiten

VisContent-Objekte erben viele Fähigkeiten von der VisualClass. Dazu gehören die Arbeit mit der Maus, der Tastatur, dem Clipboard sowie die Arbeit mit der Focus- und der Target-Hierarchie. Im Kapitel 5.1 dieses Handbuchs (Die VisualClass) finden Sie dazu eine Kurzbeschreibung sowie Verweise auf die zugehörigen Kapitel im Handbuch.

Weitere Fähigkeiten erben VisContent-Objekte von der VisGroup Class. Das sind insbesondere die Darstellung auf dem Bildschirm (Ausgabe von Text und Grafik), die Anordnung der eigenen Children sowie die Bestimmung der eigenen Größe. Die zugehörigen Instancevariablen, Methode und Actionhandler sind ausführlich im Kapitel 5.3 (VisGroup) des Objekthandbuchs beschrieben.

Besondere Hinweise für VisContent-Objekte

  • Das VisContent-Objekt gibt (wie alle R-BASIC Objekte) die Tastaturereignisse zuerst an seine Children weiter, bevor es den BASIC Tastaturhandler aufruft. Sollten beide Objekte (Content und Children) einen Tastaturhandler haben wird daher zuerst der Tastaturhandler der Children-Objekte aufgerufen und erst danach der Tastaturhandler des Content-Objekts. Im Kapitel 14.4 des Handbuchs "Spezielle Themen" ist am Beispiel eines Textobjekts beschrieben, wie man vorgehen muss, um den BASIC-Tastaturhandler aufzurufen, bevor das Objekt das Tastaturereignis an seine Children weitergibt.

  • Auch Mausereignisse werden zuerst an die Children weitergegeben, bevor der eigene BASIC Handler aufgerufen wird. Sollten beide Objekte (Content und Children) einen Maushandler haben wird daher zuerst der Maushandler der Children-Objekte aufgerufen und erst danach der Maushandler des Content-Objekts.

  • Um mit der Zwischenablage arbeiten zu können muss das VisContent-Objekt im gepufferten Modus arbeiten (Instancevariable buffered = TRUE).

  • Sie sollten die visPosition-Werte für VisContent-Objekte nicht ändern. Das kann zu unerwarteten Ergebnissen, insbesondere einer Verschiebung der Position aller beteiligten Objekte, führen.


contentAttrs

Die Instancevariable contentAttrs enthält drei Konfigurationsbits. Bits, die in der Tabelle unten nicht aufgeführt sind sollten Sie nicht setzen. Das kann zu unerwarteten Ergebnissen führen, da sie intern verwendet werden.
Syntax UI-Code: contentAttrs = attrsToSet, attrsToClear  
         Lesen: <numVar> = <obj>.contentAttrs (0)
                Die BASIC-Syntax erfordert beim Lesen von
                contentAttrs einen Parameter.
                Der Wert wird hier ignoriert.
     Schreiben: <obj>.contentAttrs = attrsToSet, attrsToClear 
    attrsToSet: zu setzende Attribute, Bitflags, siehe Tabelle
  attrsToClear: zu setzende Attribute, Bitflags, siehe Tabelle

Konstante Wert (hex)
CA_SAME_WIDTH_AS_VIEW 128 (&h80)
CA_SAME_HEIGHT_AS_VIEW   64 (&h40)
CA_VIEW_DOC_BOUNDS_SET_MANUALLY    4 (&h04)


Bedeutung der einzelnen Bits:

  • CA_SAME_WIDTH_AS_VIEW
  • CA_SAME_HEIGHT_AS_VIEW
    Das Contentobjekt passt seine Breite bzw. Höhe an die Größe des View-Objekts an, wenn das möglich ist. Häufig stellt man das View in die entsprechende Richtung dann so ein, dass es nicht scrollbar ist.

    Hinweis:
    Im Allgemeinen müssen Sie zusätzlich die Bits VSF_EXPAND_WIDTH bzw. VSF_EXPAND_HEIGHT in der Instancevariablen visSizeFlags setzen, um die gewünschte Wirkung zu erreichen. Bitte beachten Sie die Konfigurationen in den Beispieldateien.

  • CA_VIEW_DOC_BOUNDS_SET_MANUALLY
    Dieses Bit wird selten benutzt und verhindert, dass das VisContent dem View automatisch seine Größe mitteilt. Sie müssen dann die Instancevariable contentSize des View verwenden, um dem View-Objekt die Content-Größe mitzuteilen. Das View benötigt diese Information, um seine Rollbalken anzupassen.


holdsLargeText


Die Instancevariable holdsLargeText muss für das VisContent und das zugehörige View auf TRUE gesetzt werden, damit die View/VisContent Kombination mit einem LargeText Objekt zusammenarbeiten kann. Details dazu finden Sie im Kapitel 4.10.9 (VisText und LargeText) des Objekthandbuchs.
Syntax UI-Code: holdsLargeText = TRUE 
     Schreiben: <obj>.holdsLargeText = TRUE | FALSE

 

^

5.4.2 View-Content Konfiguration

Auf welche Weise ein VisContent mit seinem View interagiert, ob es seine Größe dem View anpasst oder umgekehrt, ob das gesamte Content oder nur ein Teil davon zu sehen ist, hängt sowohl von den Einstellungen des VisContent als auch ganz entscheidend von der Einstellung des View-Objekts ab.
Eine ausführliche Beschreibung alle Instancevariablen eines View finden Sie im Kapitel 4.9 des Objekthandbuchs. Die folgenden Abschnitte beschreiben typische Konfigurationen und decken einen großen Teil der Möglichkeiten ab.

^

5.4.2.1 Wenn das Content eine feste Größe hat

Typische Situationen, in der ein VisContent-Objekt eine feste Größe hat, sind z.B. eine Seite in einen Schreibprogramm oder ein Gameboard.
Um einem VisContent eine feste Größe zu geben, gibt es zwei Möglichkeiten. Entweder, Sie haben eine Objekt-Tree, dessen Objekte eine feste Position und Größe haben, oder Sie geben dem Content explizit eine feste Größe, indem sie folgende Instancevariablen im VisContent setzen:
  visSizeOptions = VSO_FIXED_SIZE
  visSize = 400, 330            ' Als Beispiel
Im letzten Fall kann das VisContent ebenfalls Children haben, muss es aber nicht.

Jeweils ein Beispiel für beide Varianten finden Sie in den Beispieldateien "VisContent Fixed Size" und "VisContent Fixed Children", im Beispiel-Ordner "Visual Class".

Wenn das Content eine feste Größe hat wird das View sich entweder der Größe des Content anpassen, oder in eine oder beide Richtungen scrollbar sein. Im Folgenden werden ein paar typische Konfigurationen dargestellt.

Um das Content in einem in beide Richtungen scrollbaren View darzustellen, muss das View folgendermaßen konfiguriert werden. Ändert der Nutzer jetzt die Größe des View, z.B. indem er die Größe des zugehörigen Hauptfensters ändert, so wird mehr oder weniger vom Content-Objekt zu sehen sein und die Rollbalken passen sich an.

View DemoView
  Content = DemoContent
  hControl = HVC_SCROLLABLE + HVC_NO_LARGER_THAN_CONTENT 
  vControl = HVC_SCROLLABLE + HVC_NO_LARGER_THAN_CONTENT 
  initialSize = 200, 200      ' zum Beispiel
End OBJECT
Um nur in eine Richtung scrollable zu sein, passen wir die Größe des Views in die andere Richtung an die des Content an.
View DemoView
  Content = DemoVisContent
  hControl = HVC_SCROLLABLE + HVC_NO_LARGER_THAN_CONTENT 
  vControl = HVC_NO_LARGER_THAN_CONTENT + \
             HVC_NO_SMALLER_THAN_CONTENT 
End OBJECT
Eine weitere Möglichkeit ist, dass das View in beide Richtungen stets exakt so groß ist, wie das Content. Um das zu erreichen gibt es zwei Möglichkeiten:
View DemoView
  Content = DemoContent
  hControl = HVC_NO_LARGER_THAN_CONTENT + \
             HVC_NO_SMALLER_THAN_CONTENT
  vControl = HVC_NO_LARGER_THAN_CONTENT + \
             HVC_NO_SMALLER_THAN_CONTENT
End OBJECT
oder
View DemoView
  Content = DemoContent
  viewAttrs = VA_VIEW_FOLLOWS_CONTENT_GEOMETRY , 0
End OBJECT
Eine besondere Situation ist, dass der Nutzer die Größe des View-Objekts verändern kann, aber stets das gesamte Content-Objekt sichtbar sein soll. Das ist z.B. für ein Gameboard interessant. Wenn der Nutzer die Größe des Spielprogramms verändert, wird stets das gesamte Spielfeld sichtbar bleiben.
Dazu muss das View seinen Zoomfaktor automatisch so ändern, dass das gesamte Content innerhalb des verfügbaren Platzes dargestellt wird. Das erreicht man, indem das Bit VA_SCALE_TO_FIT in der Instancevariablen viewAttrs gesetzt wird.
Damit das View seine Anfangsgröße kennt und anfangs einen Skalierungsfaktor von 1 einstellt, geben wir sowohl einen Wert für initialSize als auch (den gleichen Wert) für contentSize vor.

Im Folgenden werden mehrere Varianten vorgestellt, die sich in ihrem Verhalten jeweils etwas unterscheiden. Den kompletten Code finden Sie in der Beispieldatei "VisContent ScaleToFit" im Ordner "Visual Class".

Variante 1:
Die Höhe des Views soll sich der vom Nutzer eingestellten Breite anpassen.

View DemoView
  Content = DemoContent
  viewAttrs = VA_SCALE_TO_FIT, 0
  initialSize = 490,210       ' Das passt in unserem Beispiel
  contentSize = 490,210

  hControl = HVC_NO_LARGER_THAN_CONTENT
  vControl = HVC_KEEP_ASPECT_RATIO

End OBJECT 
Variante 2:
Analog zur Variante 1 soll sich die Breite des Views der vom Nutzer eingestellten Höhe anpassen.
View DemoView
  Content = DemoContent
  viewAttrs = VA_SCALE_TO_FIT, 0
  initialSize = 490,210       ' Das passt in unserem Beispiel
  contentSize = 490,210

  hControl = HVC_KEEP_ASPECT_RATIO
  vControl = HVC_NO_LARGER_THAN_CONTENT

End OBJECT
Variante 3:
Der Skalierungsfaktor orientiert sich sowohl an der Breite als auch an der Höhe des View. ' Dabei kann das View höher als das Content werden.
View DemoView
  Content = DemoContent
  viewAttrs = VA_SCALE_TO_FIT, 0
  initialSize = 490,210       ' Das passt in unserem Beispiel
  contentSize = 490,210

  hControl = HVC_NO_LARGER_THAN_CONTENT
  vControl = HVC_NO_LARGER_THAN_CONTENT

End OBJECT 
Variante 4:
SFO_BOTH_DIMENSIONS in der Instancevariablen scaleToFitOptions bewirkt, dass der Zoomfaktor in beide Richtungen unabhängig voneinander berechnet wird.
View DemoView
  Content = DemoContent
  viewAttrs = VA_SCALE_TO_FIT, 0
  initialSize = 490,210       ' Das passt in unserem Beispiel
  contentSize = 490,210

  scaleToFitOptions = SFO_BOTH_DIMENSIONS
  hControl = HVC_NO_LARGER_THAN_CONTENT
  vControl = HVC_NO_LARGER_THAN_CONTENT

End OBJECT 

^

5.4.2.2 Wenn das Content eine variable Größe hat

Typische Situationen, in den ein VisContent-Objekt eine veränderliche Größe hat sind z.B. ein Dateimanager oder der Grafikviewer Gonzo. Hier kann sich die Anzahl der dargestellten Objekte (Children des VisContent) ändern und wenn Sie die Größe des Hauptfensters verändern, ordnen sich die Children neu an.

Im Allgemeinen ist das View in diesem Fall in eine Richtung scrollbar, während sich das VisContent in der anderen Richtung an die Größe des Views anpasst. Das folgende Codefragment zeigt eine typische Konfiguration für diesen Fall. Das View passt sich der Größe seines Parent-Objekts an und ist in vertikaler Richtung scrollbar. Das Content passt sich in der Breite der Größe des View an, seine Höhe berechnet es aus der Geometrie seiner Children. Diese oder eine ähnliche Konfiguration wird in mehreren Beispielen im Ordner "Visual Class" verwendet.

View DemoView
  Content = DemoContent
  vControl = HVC_SCROLLABLE
  initialSize = 400, 250
  ExpandWidth
  ExpandHeight
  ...
End OBJECT

VisContent DemoContent
  allowChildrenToWrap = TRUE
  ' Das Content-Objekt soll immer so breit sein, wie das
  ' zugehörige View.
  ' Dazu müssen die folgenden Instancevariablen gesetzt sein.
  contentAttrs = CA_SAME_WIDTH_AS_VIEW , 0
  visSizeFlags = VSF_EXPAND_WIDTH
  ...
End OBJECT

^

5.4.3 Anlegen und Vernichten von Objekten

Methoden:

Methode Aufgabe
CreateVisObject Neues VisObj-Objekt anlegen
DestroyVisObject Mit CreateVisObject VisObj-Objekt vernichten

Im Zusammenhang mit VisObj-Objekten ist es sehr häufig, dass Sie VisObj-Objekte zur Laufzeit anlegen und wieder vernichten müssen. Ein Beispiel ist der GeoMananger, der für jede Datei im Verzeichnis ein eigenes VisObj-Objekt verwendet. Auch der Grafikviewer Gonzo legt für jede gefundene Grafikdatei ein VisObj-Objekt an und vernichtet es wieder, wenn das Verzeichnis gewechselt wird.

Natürlich können Sie die im Kapitel 2.1.5 des Objekthandbuchs beschriebenen Routinen CreateObject und DestroyObject auch für VisObj-Objekte benutzen. Sie müssen sich dann aber auch um das Anlegen und die Verwaltung der zugehörigen Objektblöcke kümmern. Insbesondere, wenn Sie viele Objekte anlegen wollen bzw. deren Anzahl vorher nicht kennen, kann das sehr aufwändig sein.

Aus diesem Grund bietet das VisContent Objekt zwei Methoden, mit denen Sie VisObj-Objekte zur Laufzeit ganz einfach anlegen und wieder vernichten können. Das VisContent managed die erforderlichen Objektblöcke dabei selbständig. CreateVisObject legt ein neues VisObj-Objekt an und bindet es bei Bedarf als Child des VisContent in den visual Tree ein. DestroyVisObject vernichtet ein mit CreateVisObject angelegtes VisObj-Objekt wieder.

CreateVisObject

Die Methode CreateVisObject legt ein neues VisObj-Objekt an und bindet es bei Bedarf als Child des VisContent in den visual Tree ein. Falls erforderlich wird ein neuer Objektblock angelegt.
Syntax: <objVar> = <obj>.CreateVisObject xSize, ySize [,addAsChild]
        xSize: Anfängliche Breites des neu angelegten Objektes
        ySize: Anfängliche Höhe des neu angelegten Objekts
   addAsChild: Objekt als Child des VisContent in den visual Tree
               einbinden (TRUE) oder nicht (FALSE).
               Der Defaultwert ist TRUE, d.h. das Objekt wird als
               letztes Child des VisContent eingebunden.

 
Um Objekte, die mit der Methode CreateVisObject angelegt wurden, zu vernichten, müssen Sie die Methode DestroyVisObject verwenden. Verwenden Sie niemals die Routine DestroyObject dafür. Allerdings ist es zulässig ein Programm zu beenden, ohne die angelegten VisObj-Objekte zu vernichten.

Nachdem das Objekt angelegt wurde, muss es noch weiter initialisiert werden. Im Allgemeinen benötigt es einen OnDraw-Handler sowie häufig einen OnMouseButton-Handler.

Nachdem alle gewünschten VisObj-Objekte angelegt wurden, müssen Sie den visual Tree aktualisieren, indem Sie die Methode MarkInvalid für das VisObj-Objekt oder das VisContent aufrufen. Erst dann erscheinen die neu angelegten Objekte auf dem Schirm.

Beispiel. Den vollständigen Code finden Sie in der Beispieldatei "Create VisObj Demo".

BUTTONACTION DemoCreateChild
DIM obj AS OBJECT

  obj = DemoContent.CreateVisObject 160, 100

  ' Initialisieren: Drawhandler, Maushandler usw.
  obj.OnDraw =  VisObjDraw
  <mehr ...ausgelassen>

  ' Das neue Objekt auf dem Schirm sichtbar machen
  obj.MarkInvalid

End ACTION ' DemoCreateChild
Im Modus customManageChildren ist es häufig sinnvoll, das neue VisObj nicht als letztes, sondern als erstes Child des VisContent einzubinden, damit es über allen schon vorhandenen Objekten gezeichnet wird. Dazu ist es sinnvoll (aber nicht erforderlich), die Methode CreateVisObject mit dem Parameter addAsChild = FALSE aufzurufen. Abschließend weisen wir das VisContent als Parent zu, wobei als Child-Position der Wert Null verwendet wird. Außerdem müssen wir dem Objekt eine visPosition zuweisen. Im Beispiel berechnen wir sie aus der Anzahl der Children, die das DemoContent schon hat. Um das Objekt sichtbar zu machen, müssen wir abschließend die Methode MarkInvalid aufrufen.

Beispiel. Den kompletten Code finden Sie in Beispieldatei "Create Custom Managed VisObj".

DIM obj AS OBJECT
DIM n

  obj = DemoContent.CreateVisObject 80, 60, FALSE
  obj.Parent = DemoContent, 0

  n = DemoContent.numChildren - 1
  obj.visPosition = 20*n + 10, 20*n+ 10

  ' Initialisieren: DrawHandler, Maushandler
  < .. siehe Beispiel-Datei ..>

  obj.MarkInvalid

End ACTION ' DemoCreateChild
Dynamisch mit CreateVisObject angelegten Objekte lassen sich ohne Einschränkungen genauso verwenden, wie statisch im UI-Code deklarierte Objekte. Es ist also möglich, aus den neu angelegten VisObj-Objekten einen komplexen Tree aufzubauen. Dazu müssen Sie einfach die Instancevariable parent des VisObj-Objekts entsprechend setzen. Außerdem ist es zulässig, dynamisch mit CreateVisObject angelegte Objekte mit statisch im UI-Code deklarierten Objekten in einem Tree zu vermischen.

DestroyVisObject

Die Methode DestroyVisObject vernichtet ein mit der Methode CreateVisObject angelegtes Objekt. Enthält der zugehörige Objektblock danach keine Objekte mehr, so wird er automatisch freigegeben.
Syntax: <obj>.DestroyVisObject <objVar>
        <objVar>: Referenz auf ein mit CreateVisObject
                  angelegtes VisObj-Objekt

 
Sie können DestroyVisObject nur mit Objekten verwenden, die von CreateVisObject angelegt wurden. Andernfalls kommt es zu einem Laufzeitfehler.
Sie können ein VisObj-Objekt vernichten, wenn es noch mit seinem Parent verlinkt ist. Allerdings darf es keine Children haben, sonst kommt es zu einem Laufzeitfehler.

Wenn Sie ein Objekt mit DestroyVisObject vernichten, müssen Sie im Modus "customManageChildren" die Methode MarkInvalid aufrufen, damit das Objekt vom Bildschirm verschwindet. Im normalen Modus ist dies nicht nötig, der visual Tree stellt sich automatisch neu dar.

Beispiel: Das letzte Child eines VisContent-Objekts soll vernichtet werden.

SUB DestroyLastChild
DIM ob as OBJECT
DIM count

  count = DemoContent.numChildren
  IF count = 0 THEN RETURN        ' Keine Children mehr

  ' Die Zählung der Children beginnt bei Null
  ' -> Das letzte Child hat die Nummer count-1
  ob = DemoContent.children(count-1)
  DemoContent.DestroyVisObject ob

End SUB
Beispiele für die Verwendung von DestroyVisObject finden Sie in den Beispieldateien "Create VisObj Demo" und "Create Custom Managed VisObj".

^

Weiter...