5.4 VisContent5.4.1 Grundlegende Fähigkeiten 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.
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:
Methoden:
^5.4.1 Grundlegende FähigkeitenVisContent-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
contentAttrsDie 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
Bedeutung der einzelnen Bits:
holdsLargeTextDie 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 KonfigurationAuf 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 hatTypische 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:
| |||||||||||||||||||||||
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 hatTypische 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 ObjektenMethoden:
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.
CreateVisObjectDie 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.
DestroyVisObjectDie 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".
^ |