3.4 Die "Apply"-Message

3.4.1 Manuelles Auslösen der Apply-Message

3.4.2 Delayed Mode und Status-Message


Einige R-BASIC Objekte enthalten Informationen oder Daten, die vom Nutzer geändert werden können und dann 'zur Anwendung' gebracht werden, indem das Objekt eine Message aussendet (d.h. den zugehörigen ActionHandler aufruft). Diese Message heißt 'Apply-Message' bzw. der Handler 'ApplyHandler' (engl. to apply: anwenden). Das sind konkret die folgenden Objekt-Klassen. Eine ausführliche Beschreibung der Objekte finden Sie im Kapitel 4 dieses Handbuchs.
  • Das Number-Objekt stellt eine Zahl dar, die vom Nutzer verändert werden kann. Drückt der Nutzer im Eingabefeld des Text-Objekts die Enter-Taste oder klickt er auf die 'Pfeile', so wird die Apply-Message gesendet, d.h. der ApplyHandler wird aufgerufen.

  • Die Text-Objekte Memo und InputLine enthalten einen Text. Drückt der Nutzer z.B. im InputLine Objekt die Enter-Taste, so wird die Apply-Message gesendet.

  • Die Listen-Objekte OptionGroup, RadioButtonGroup und DynamicList. Hier wird die Apply-Message gesendet wenn der Nutzer einen Listeneintrag anwählt.
Neben einem ApplyHandler besitzen diese Objektklassen auch eine StatusHandler, der im 'delayed Mode' (siehe nächstes Kapitel) benötigt wird.

Instancevariable Syntax im UI-Code Im BASIC-Code
ApplyHandler ApplyHandler = <Handler> nur schreiben
StatusHandler StatusHandler = <Handler> nur schreiben

^

3.4.1 Manuelles Auslösen der Apply-Message

Die ApplyHandler der oben angegebenen Objekte sind bei den entsprechenden Objekten definiert und werden dort ausführlich besprochen, da sie je nach Objekt unterschiedliche Parameter haben.

Es gibt jedoch eine auf GenericClass-Ebene definierte Methode und zwei dazugehörige Instance-Variablen, die ein manuelles auslösen der Apply-Message bei Bedarf, d.h. vom BASIC-Code aus, ermöglicht.

Methoden:

Methode Aufgabe
Apply Auslösen der Apply-Message

Syntax BASIC-Code: <obj>.Apply

Instance-Variablen

Hint Syntax im UI-Code Im BASIC-Code
ApplyEvenIfNotModified ApplyEvenIfNotModified --
ApplyEvenIfNotEnabled ApplyEvenIfNotEnabled --

Syntax UI-Code: ApplyEvenIfNotModified
                ApplyEvenIfNotEnabled

 

Apply

Die Methode Apply fordert ein Objekt auf, seine Apply-Message zu senden (d.h. seinen ApplyHandler aufzurufen). Objekte, die von Hause aus keinen ApplyHandler haben (wie z.B. Group's, Dialog- und Primary-Objekte) reichen diese Methode an ihre Children weiter. Das heißt konkret, dass es ausreicht die Apply-Methode eines Group-Objekts aufzurufen und alle seine Children bzw. deren Children usw. senden ihre Apply-Message aus, falls sie eine besitzen. Dieses Konzept ist bei genauerer Betrachtung extrem leistungsfähig, da man sich dadurch viel Arbeit ersparen kann.

Wichtig 1: Die oben angegeben Objekte (Number, Text- und Listen-Objekte) senden ihre Apply-Message nur dann aus, wenn sie 'modified' (geändert) sind. Ändert der Nutzer das Objekt, klickt er z.B. einen Listeneintrag an, so passiert das automatisch. Vom Basic-Code aus müssen wir aber i.A. selbst dafür sorgen, das Objekt auf 'modified' zu setzen. Alle betroffenen Objekte besitzen eine entsprechende Instance-Variable.

Wichtig 2: Nachdem das Objekt seine Apply-Message ausgesendet hat wird der 'modified'-Zustand automatisch zurückgesetzt.

Beispiel: Nehmen wir an, wir haben eine Listen-Objekt namens DefaultOptions. Von diesem soll beim Programmstart ein bestimmter Eintrag selektiert werden, der z.B. aus einer Datei gelesen wurde und daher nicht von vorneherein bekannt ist. Dann soll die Liste ihre Apply-Message aussenden um den Rest des Programms über ihren Zustand zu informieren. Das Belegen der passenden Instance-Variable namens 'selection' macht die Liste aber nicht 'modified'. Damit sie ihre Apply-Message aussendet müssen wir das selbst tun. Das Ganze verpacken wir in eine SUB namens InitList:

SUB InitList (entry as INTEGER) 
    DefaultOptions.selection = entry
    DefaultOptions.modified = TRUE
    DefaultOptions.Apply
    END SUB

ApplyEvenIfNotModified, ApplyEvenIfNotEnabled

Wie oben erwähnt muss ein Objekt, dass eine Apply-Message aussenden soll 'modified' sein. Die Hints ApplyEvenIfNotModified bzw. ApplyEvenIfNotEnabled sorgen dafür, dass ein Objekt seine Apply-Message beim Aufruf der Apply-Methode auch dann aussendet, wenn es nicht 'modified' oder sogar nicht 'enabled' ist. Diese Hints sind zwar auf GenericClass-Level definiert, zeigen aber nur bei den Objekten, die auch über einen Apply-Handler verfügen, eine Wirkung.

^

3.4.2 Delayed Mode und Status-Message

Das im Folgenden beschriebenen Eigenschaften und Verhaltensweisen von Objekten sind - richtig eingesetzt - sehr leistungsfähig und können dem Programmierer viel Arbeit ersparen, sie erfordern jedoch ein gutes Überblickswissen über das R-BASIC Objektsystem. Sie sind daher eher etwas für den fortgeschrittenen Programmierer. Meistens ist die gleiche Funktionalität auch anders, dann allerdings mit etwas mehr Programmcode, erreichbar.

Wie oben erwähnt senden die anfangs aufgeführten Objekte (Number, Text- und Listen-Objekte) ihre Apply-Message sofort aus, wenn der Nutzer z.B. eine Listeneintrag auswählt oder auf einen 'Pfeil' eines Number-Objekts klickt. Es gibt jedoch auch Situationen, in denen dieses sofortige Reagieren nicht erwünscht ist. In einem komplexen Dialog, in dem z.B. Farbe, Form und Größe eines Objekts eingestellt werden, kann es sinnvoll sein, dass der Nutzer zunächst alle Einstellungen vornimmt und diese Einstellungen dann 'auf einmal' angewendet werden sollen. Hinzu kommt, dass gegebenenfalls zwei oder mehrere Objekte voneinander abhängen. In einen 'Drucken'-Dialog z.B. muss sichergestellt werden, dass die erste zu druckende Seitennummer nicht größer als die letzte zu druckende Seitennummer ist. Die entsprechenden Number-Objekte müssen also miteinander kommunizieren, ohne dass die Änderungen 'angewendet' (d.h. die Seiten gedruckt) werden.

In R-BASIC wird dieses Verhalten als Delayed Mode bezeichnet (engl. to delay: verzögern). Die eigentliche Apply-Message der betroffenen Objekte wird verzögert, nämlich erst auf Anforderung, ausgesendet. Statt ihrer Apply-Message senden die entsprechenden Objekte zunächst eine sogenannte Status-Message aus, d.h. es wird der StatusHandler aufgerufen. Dieser kann genutzt werden, um andere Objekte zu informieren. Die entsprechende Instance-Variable (StatusHandler) ist genau wie der ApplyHandler bei den jeweiligen Objekten definiert.

Instance-Variable Syntax im UI-Code Im BASIC-Code
MakeDelayedApply MakeDelayedApply --


Syntax UI-Code: MakeDelayedApply

Die auf GenericClass-Ebene definierte Instance-Variable MakeDelayedApply versetzt ein Objekt und seine Children in den Delayed Mode. Sehr häufig ist es deshalb so, dass ein Group-Objekt diese Anweisung im UI-Code erhält, so das alle seine Children, deren Children usw. im Delayed Mode arbeiten. Um die Apply-Message der betroffenen Objekte auszusenden reicht es, die Apply-Methode des Group-Objekts aufzurufen, da diese, wie im vorherigen Abschnitt beschrieben, an alle Children weitergegeben wird.

Beispiel: Eine Gruppe von Objekten innerhalb der Group 'BottomGroup' arbeitet im Delayed Mode. Die beiden Number-Objekte kommunizieren über Status-Handler miteinander. Der ApplyButton löst ein 'Anwenden' (Aufruf der ApplyHandler) aus.

...

UI-Code

Group BottomGroup
    Children = Memo1, RightGroup
    orientChildren = ORIENT_HORIZONTALLY
    DrawInBox
    MakeDelayedApply    ' wird an die Children weitergereicht 
    END Object

Group RightGroup
    Children = Number1, Number2, ApplyButton
    orientChildren = ORIENT_VERTICALLY
    justifyChildren = J_RIGHT + J_BOTTOM
    ExpandHeight
    END Object

Number Number1
    Caption$ = "Von "
    ApplyHandler = NumberVonHandler
    StatusHandler = StatusNum1
    END Object

Number Number2
    Caption$ = "Bis "
    ApplyHandler = NumberBisHandler
    StatusHandler = StatusNum2
    END Object

Button ApplyButton
    Caption$ = " Anwenden"
    ActionHandler = DoApply
    END Object    

Memo Memo1    
    Caption$ = "Note:"
    justifyCaption = J_TOP
    text$ ="Hier Text eingeben ..."
    fixedSize = 30 + ST_AVG_CHAR_WIDTH, 5 + ST_LINES_OF_TEXT
    ApplyHandler = txtAction
    END Object


Basic-Code

NUMBERACTION NumberVonHandler
    Print "Von:";value
    END ACTION

NUMBERACTION NumberBisHandler
    Print "Bis:";value
    END ACTION

NUMBERACTION StatusNum1
    IF value > Number2.value THEN
    Number2.value = value
    Number2.modified = TRUE    ' wurde verändert!
    END IF 
    END ACTION

NUMBERACTION StatusNum2
    IF value < Number1.value THEN
    Number1.value = value
    Number1.modified = TRUE    ' wurde verändert!
    END IF 
    END ACTION

BUTTONACTION DoApply
    BottomGroup.Apply
    END Action
Wenn Sie dieses Beispiel testen werden Sie feststellen, dass
  • Die ApplyHandler nur gerufen werden, wenn das entsprechende Objekt vorher geändert (modifiziert) wurde.

  • Ein zweites Anklicken des ApplyButtons nichts bewirkt, es sei denn, Sie haben eins der Objekte zwischendurch wieder geändert.
Das ist aus Performance-Gründen so und liegt daran, dass, wie letzten Abschnitt beschrieben, ApplyHandler nur gerufen werden, wenn das Objekt 'modified' ist. Wenn Sie möchten, dass die ApplyHandler auf jeden Fall gerufen werden, egal ob das Objekt modified ist oder nicht, können Sie die Hints ApplyEvenIfNotModified bzw. ApplyEvenIfNotEnabled aus dem letzten Kapitel verwenden.

Beispiel UI-Code

Number Number2
    Caption$ = "Bis "
    ApplyHandler = NumberBisHandler
    StatusHandler = StatusNum2
    ApplyEvenIfNotModified 
    END Object
Bei Bedarf ist es möglich, die StatusMessage manuell auszulösen. Dazu wird die Methode SendStatus verwendet. Diese Methode ist für die oben genannten Objektklassen definiert. Das sind: Number, Memo, InputLine, OptionGroup, RadioButtonGroup und DynamicList.

Methode Aufgabe
SendStatus Auslösen der Status-Message


Syntax BASIC-Code: <obj>.SendStatus

Hinweis für Dialog-Objekte: Natürlich können Sie ganze Dialogboxen mit dem Hint MakeDelayedApply in den Delayed Mode versetzen. Häufig ist es aber besser stattdessen die Dialog-Instance-Variable dialogType auf den Wert DT_DELAYED_APPLY zu setzen. Dadurch erzeugt der Dialog automatisch einen Apply-Button, und nimmt Ihnen auch sonst viel Arbeit ab. Eine ausführliche Beschreibung zum Dialog-Objekt finden Sie im Kapitel 4.6, der Delayed Mode für Dialoge ist im Kapitel 4.6.6.5 beschrieben.

Schlussbemerkung: Der Delayed Mode ist angebracht und sehr effektiv, wenn die betroffenen Objekte ihre Apply-Message einzeln und unabhängig voneinander senden sollen. Für den Fall, dass Sie erst die Informationen von allen beteiligten Objekten sammeln müssen, bevor Sie fortfahren können, ist es eventuell sinnvoller den Objekten gar keinen ApplyHandler zu geben und die Informationen direkt von den Objekten abzufragen, wie in folgendem Codebeispiel gezeigt:

BUTTONACTION DoApply
DIM  von, bis, info$    
    von = Number1.value
    bis = Number2.value
    info$ = Memo1.text$
    <.. Auswertung ..>
    END Action

^

Weiter...