In diesem zweiten Teil unserer Serie wollen wir ganz besonders auf den Objektstatus und die Objektflags eingehen. Speziell die Flags sind für eine vernünftige Handhabung von Dialogboxen von großer Bedeutung. Durch sie lassen sich u.a. wechselseitig umschaltende Buttons (Radiobuttons) verwirklichen oder auch ganze Teile einer Dialogbox ein- und ausblenden. Leider gab es im ersten Teil dieser Serie bei den Erklärungen ein paar vertauschte Spalten, so daß man sich z.B. die Erklärung zur TEDINFO teilweise selbst zusammensuchen mußte. Wir bitten dies zu entschuldigen.
Wir hoffen auf Verständnis, wenn wir die Prozeduren aus dem ersten Teil dieser Serie nur benutzen und nicht mehr erklären. Die alten Routinen werden auch im Li-sting nicht mehr abgedruckt, sondern sind aus dem ersten Teil zu ergänzen, da ansonsten die Listings endlos lang und nur unnötig Platz verschwenden würden. Am Anfang der Erklärungen zu den beiden Beispielprogrammen findet sich immer eine Liste mit den verwendeten alten Routinen, so daß das Ergänzen nicht allzu schwer sein dürfte. Auch für die Erstellung der beiden Resource-Dateien gibt es wieder zwei Bilder, die genau beschreiben, welche Objekttypen (in Klammern) benötigt werden und welche Namen vergeben werden sollten (kursiv). Ferner sind zwei Tabellen vorhanden, in denen aufgelistet ist, welche Flags bei der Erstellung des Resource für die Objekte gesetzt werden müssen.
Doch zuerst einmal wieder ein bißchen Theorie bevor es ans Programmieren geht. Dazu muß man sich mit der Objektstruktur beschäftigen. Wir haben bereits in der Juni-Ausgabe der ST Computer festgestellt, daß jedes Objekt einen 24 Bytes also 12 Worte großen Eintrag besitzt. Wie dieser Eintrag nun aufgebaut ist, zeigt uns Tabelle 1.
Wort 0: ob_next — Index des nächsten Objektes in der gleichen Ebene
Wort 1: ob_head — Index des ersten Objektes in der nächsten Ebene
Wort 2: ob_tail — Index des letzten Objektes in der nächsten Ebene
Wort 3: ob_type — Objekttyp (z.B. Button, G_Box)
Wort 4: ob_flags — Objektflags (z.B. Hidetree, Editable)
Wort 5: ob_state — Objektstatus (z.B. Selected, Disabled)
Wort 6 + 7: ob_spec — Objektsspezifikation (nutzen wir zum Errechnen der TEDINFO-Adresse)
Wort 8: ob x — X-Koordinate des Objekts relativ zum Vorgänger (beim ersten Objekt (Wurzel oder auch Root) = 0)
Wort 9: ob_y — Y-Koordinate des Objektes (gleiche Bedingungen wie ob_x)
Wort 10: ob_width — Breite des Objektes
Wort 11: ob_height — Höhe des Objektes
Uns interessieren in dieser Folge die Einträge ob_flags, ob_state, ob_width und ob_height, da sie in den neu vorgestellten Routinen benutzt werden. Wort 6 und 7 (ob_spec) haben wir ja bereits in der letzten Folge in der Ptadr-Routine benötigt. Alle anderen Worte lassen wir vorerst einmal unberührt. Grundsätzlich kann man die Einträge der Objektstruktur mit der folgenden Methode auslesen:
Worteintrag = Dpeek (Objektadresse + erstes Byte des Wortes)
Hierbei gilt Objektadresse = Baumadresse + 24 X Objektindex. Ferner ist unter dem „ersten Byte“ das Byte zu verstehen, mit dem der jeweilige Eintrag beginnt. Da ein Wort ja aus zwei Bytes besteht, muß man nur den Wortindex mit Zwei multiplizieren. Um z.B. die Objektflags auszulesen, müßte man 4x2 = 8 rechnen (Wort 4 = ob_flags) und das würde folgendermaßen aussehen:
ob_flags = Dpeek (Objektadresse + 8)
Diese Berechnung der Objektstruktureinträge findet sich in den Routinen immer wieder. Will man den ob_spec-Eintrag auslesen, muß man allerdings darauf achten, daß dieser zwei Worte also vier Bytes bzw. ein Langwort lang ist und somit statt einem Dpeek ein Lpeek angewandt werden muß (siehe Ptadr-Routine im Teil I). Beachtet man dies nicht, erhält man nur die erste Hälfte des Langwortes und eine gänzlich falsche Adresse.
Genauso wie man die Objektstruktur auslesen kann, ist es natürlich auch möglich in diese wieder hineinzuschreiben. Man benützt dazu den Dpoke-Befehl (Ausnahme ist wieder ob__spec). So kann man leicht die Objektflags oder den Objektstatus verändern. Natürlich sollte man die Veränderungen nur durch logische Verknüpfungen bewirken, da ansonsten unwissentlich oder unbeabsichtigt andere Bits gelöscht werden, die man vielleicht noch später braucht. Also gilt als erste Regel, immer zuerst den alten Wert aus dem Speicher lesen (Peek), anschließend das gewünschte Bit durch logische Verknüpfung setzen bzw. löschen und dann erst den neuen Wert zurückschreiben (Poke).
Zum Löschen eines Bits nimmt man dann folgende zwei Programmzeilen:
Wort = Dpeek (Objektadresse + erstes Byte)
Dpoke Objektadresse + erstes Byte, Wort And Not Bit
Das gelesene Wort wird also mit einer logischen NAND-Verknüpfung (Not AND) gelöscht.
Will man dagegen ein Bit setzen, muß das ausgelesene Wort mit dem Bit verodert ()Or) werden. Die zweite Zeile würde dann so aussehen:
Dpoke Objektadresse + erstes Byte, Wort Or Bit
Man kann natürlich auch ein Wort auf ein bestimmtes Bit überprüfen. Dazu muß man das gelesene Wort mit dem Bit verenden (And). Ist das Ergebnis ungleich Nul so ist das Bit gesetzt. Das sieht dann folgendermaßen aus:
Wort = Dpeek (Objektadresse + erstes Byte)
Ergebnis = Wort And Bit
Wenn man sich nun die neuen Prozeduren dieser Folge ansieht, wird man sogleich für alle diese Anwendungen die passenden Routinen finden. Auf sie werden wir gleich ausführlich eingehen. Doch zunächst möchten wir zeigen, welche Bits von ob_flags und ob_state welche Bedeutung haben, da diese wohl am häufigsten bei der Programmierung von Dialogboxen benutzt werden. Dazu schauen wir uns zunächst einmal Tabelle 2 und 3 an.
Bit | Name | Dez | Hex |
---|---|---|---|
Bit 0: | SELECTABLE | 1 | &H1 |
Bit 1: | DEFAULT | 2 | &H2 |
Bit 2: | EXIT | 4 | &H4 |
Bit 3: | EDITABLE | 8 | &H8 |
Bit 4: | RADIOBUTTON | 16 | &H10 |
Bit 5: | LASTOB | 32 | &H20 |
Bit 6: | TOUCHEXIT | 64 | &H40 |
Bit 7: | HIDETREE | 128 | &H80 |
Bit 8: | INDIRECT | 256 | &H100 |
Bit 9: | nicht benutzt | 512 | &H200 |
Bit 10—15 | nicht benutzt |
Die meisten Namen dieser beiden Tabellen werden uns sehr bekannt Vorkommen, denn sie begegnen uns fast alle in jedem Resource Construction Set. Dies bedeutet, daß man Objektflags und Objektstatus sowohl in einem RCS vorwählen, als auch später im Programm verändern kann. Die jeweilige Bedeutung der Bits müßte jedem, der mit einem RCS schon gearbeitet hat, weitestgehend vertraut sein. Deswegen werden sie hier nicht noch einmal ausführlich erklärt. Für diejenigen, die damit nichts anfangen können, sei auf das Sonderheft der ST Computer verwiesen, daß seit Ende Juni zu beziehen ist.
Da jedes Bit einer Zweierpotenz entspricht, haben wir hinter den Namen gleich die Ergebnisse dieser Zweierpotenzen sowohl dezimal als auch hexadezimal angegeben. In dieser Serie werden wir die hexadezimale Schreibweise (&H) vorziehen.
Weiterhin sind einige Bits nicht benutzt, wodurch sie für den eigenen Gebrauch frei werden. Wir möchten dafür nicht unsere Hand ins Feuer legen, allerdings sind bei uns noch keine Probleme durch die Benutzung aufgetreten. Aber da diese Bits nirgendwo dokumentiert sind, könnte sich irgendwann mal ein Fehler einschleichen. Im RCS der englischen Firma KUMA lassen sich diese Bits sogar schon direkt bei der Erstellung des Resource setzen. Ein Beispiel für den eigenen Gebrauch dieser freien Bits kann man in den Prozeduren Hide und Unhide in Listing 2 sehen, bei denen Bit 9 der Objektflags als Hilfsflag dient. Vielleicht werden die freien Bits später einmal bei einer eventuellen Erweiterung des GEMs genutzt, aber darauf sollte man im Moment keine Rücksicht nehmen. Wer weiß, ob so eine Änderung jemals stattfindet.
Bit | Name | Dez | Hex |
---|---|---|---|
Bit 0: | SELECTED | 1 | &H1 |
Bit 1: | CROSSED | 2 | &H2 |
Bit 2: | CHECKED | 4 | &H4 |
Bit 3: | DISABLED | 8 | &H8 |
Bit 4: | OUTLINED | 16 | &H10 |
Bit 5: | SHADOWED | 32 | &H20 |
Bit 6—15 | nicht benutzt |
Um ein möglichst einfaches Handling der Flags (auch bei ob_state handelt es sich um Flags, nämlich um Statusflags) beim Programmieren von Dialogboxen zu gewährleisten, kann man in dieser Ausgabe wieder eine Reihe nützlicher Routinen finden, die im folgenden beschrieben werden.
Doch zunächst möchten wir noch auf eine kleine Änderung in der Routine Objc_draw hinweisen. Hier wurde noch die Abfrage auf das Flag Rette% ergänzt, das bewirkt, daß der Bildschirmhintergrund nicht mehr gerettet wird, sondern nur dann, wenn Rette% einen Wert von 1 zugewiesen bekommen hat. Dies erweis sich in unserem Beispielprogramm als notwendig, da Objc_draw mehrfach mit verschiedenen Koordinaten aufgerufen wird und deswegen nur beim ersten Zeichen der Dialogbox der Hintergrund gespeichert werden soll. Dieses Flag Rette% ist noch keine Patentlösung, aber erfüllt in diesem Falle seinen Zweck.
Do_objc — Setzen eines Statusflags (ob_state)
Do_objc (Baumadresse%, Objektindex%, Bitwert%)
Viel gibt es bei dieser Routine nicht mehr zu erklären, da das Wesentliche bereits gesagt wurde (siehe Abschnitt „Schreiben in die Objektstruktur“). Als Parameter werden die Baumadresse, der Objektindex und der Wert des Bits benötigt. Übergeben werden kann sowohl der Dezimal- als auch der Hexadezimalwert, je nach Belieben.
Undo_objc — Löschen eines Statusflags (ob_state)
Undo_objc (Baumadresse%, Objektindex%, Bitwert%)
siehe Do_objc
Is_objc — Überprüfen eines Statusflags (ob_state)
Is_objc (Baumadresse%, Bitwert%, *Ergebnis%)
Diese Routine überprüft, ob ein Statusflag gesetzt ist. Dies ist vor allem nötig, um zu sehen, ob ein bestimmter Button selektiert wurde (Bit 0) und dann entsprechend darauf zu reagieren. Doch auch die anderen Statusflags können bei Dialogboxen Verwendung finden. Man denke da nur an das DISABLED-Flag, durch das ein Objekt „ausgeschaltet“ werden und somit nicht mehr mit der Maus selektiert werden kann. Es erscheint dann grau gezeichnet. So kann man zum Beispiel einen Button „disablen“, wenn dieser nicht mehr anwählbar sein soll.
A_Button Selectable, Radio Butn
B_Button Selectable, Radio Butn
C Button Selectable, Radio Butn
OK Selectable, Default, Exit
Als Parameter finden hier wieder die Baumadresse und der Objektindex Verwendung. Ferner wird der Bitwert übergeben. Als Ergebnis erhält man dann, wenn das Flag gesetzt ist, den Bitwert zurück. Ist der Rückgabewert eine Null, so ist das Flag gelöscht.
Set_flag — Setzen eines Objektflags (ob_flags)
Set_flag (Baumadresse%, Objektindex%, Bitwert%)
Auch zu dieser Routine ist eigentlich schon genug gesagt. Mit 0 wird ein Objektflag in der Objektstruktur gesetzt. Als Parameter dienen wieder die Baumadresse, Objektindex und der Bitwert.
Del_flag — Löschen eines Objektflags (ob_flags)
Del_flag (Baumadresse%, Objektindex%, Bitwert%)
Siehe Set_flag
Is_flag — Überprüfen eines Objektflags (ob_flags)
Is_flag (Baumadresse%, Objektindex%, Bitwert%, *Ergebnis%)
Diese Routine funktioniert äquivalent zu der Is_objc-Routine, mit dem einzigen Unterschied, daß hier ein Objektflag statt einem Objektstatus überprüft wird. Bei der Vielfalt der Möglichkeiten, die die Objektflags bieten, braucht man wohl keine Anwendungsbereiche angeben. Fiier ist der Phantasie freien Lauf gegeben.
Objc_offset — Berechnen der absoluten X, Y-Koordinaten relativ zum Bildschirm
Objc_offset (Baumadresse%, Objektindex%, *X%, *Y%)
Diese Routine ist in dieser Folge die einzigste Original-AES-Routine (Gemsys 44). Sie wird zum Berechnen der absoluten X, Y-Koordinaten eines Objektes auf dem Bildschirm angewandt. Wir benötigen sie in unserer Get_objc_xywh-Routine, auf die wir gleich noch kommen. Leider kann man die X, Y-Koordinaten nicht direkt aus der Objektstruktur lesen, da Wort 8 und 9 nur die relativen X, Y-Koordinaten liefern und somit für unsere Zwecke unbrauchbar sind. Denn wir benötigen die absoluten Koordinaten und nicht die, die sich auf das übergeordnete Objekt beziehen.
Als Parameter übergeben wir die Baumadresse und den Objektindex. Zurück bekommen wir daraufhin die absoluten X, Y-Koordinaten.
Get_objc_xywh — Ermitteln der X, Y, W, H-Koordinaten eines Objektes
Get_objc_xywh (Baumadresse%, Objektindex%, *X%, *Y%, *Breite%, *Höhe%)
Durch diese Routine erhalten wir alle wichtigen Koordinaten, um ein einzelnes Objekt neu zu zeichnen. Zunächst wird die Objc_offset-Routine aufgerufen, wodurch wir die X, Y-Koordinaten des Objektes erhalten. Anschließend wird direkt aus der Objektbaumstruktur die Breite (Wort 10, „erstes Byte“ = 20) und die Höhe (Wort 11, „erstes Byte“ = 20) des Objektes ermittelt.
Als Parameter benötigen wir die Baumadresse und den Objektindex. Zurück gegeben werden X, Y-Koordinaten, Breite und Höhe des Objektes.
Objc_update — Neuzeichnen eines einzelnen Objektes
Objc_update (Baumadresse%, Objektindex%)
Die Routine besteht nur aus zwei Prozeduraufrufen. Zunächst werden die Koordinaten des Objektes durch die Get_objc_xywh-Routine ermittelt. Daraufhin erfolgt ein Objc_draw-Aufruf mit dem Objektindex und den erhaltenen Koordinaten. Somit wird nur der durch die Koordinaten beschriebene Bereich neu gezeichnet.
Benötigt werden als Parameter nur die Baumadresse und der Objektindex.
Unhide — Einblenden eines Teils der Dialogbox
Unhide (Baumadresse%, Objektindex%)
Zu dieser Routine gibt es eine ganze Menge zu erklären. Zunächst einmal ist schon die Erstellung im RCS nicht ganz ohne Schwierigkeiten zu bewältigen, da man darauf achten sollte, daß der Teil der Dialogbox, der aus- bzw. eingeblendet werden soll, immer von einer Box des Typs G_Box (mit Rand) oder G_ibox (ohne Rand) umgeben ist. D.h. eigentlich müßte man sagen, daß die aus-/einzublendenden Objekte in der Box liegen. In unserem Beispiel haben wir eine G_Box (mit Rand) genommen, um zu zeigen, daß eben solch eine Box notwendig ist. In den meisten Fällen würde man aber ein G_ibox vorziehen, da dieses keinen sichtbaren Rand (das i bei G_ibox kommt vom englischen invisible) hat und so das Boxteil aus dem Nichts erscheint. Man kann das Beispiel ruhig mal entsprechend verändern, indem man die G_box gegen eine G_ibox vertauscht.
Der Grund dafür, daß eine Box benötigt wird, liegt allein an der Optik. Da nach jedem Ändern eines Status oder auch eines Flags ein erneuter Objc_draw-Aufruf erfolgen muß, um das Ergebns auf dem Bildschirm zu sehen, wird somit die Dialogbox neu gezeichnet. Dies würde normalerweise zeitbedingt ein häßliches Flackern der ganzen Dialogbox ergeben. Nun kommt der Trick der ganzen Sache. Um dieses Flackern zu vermeiden, zeichnet man nur einen Teil der Dialogbox neu und zwar den Teil, der von unserer G_box bzw. G_ibox umgeben ist. Dazu haben wir uns die bereits oben erklärte Routine Objc_update geschrieben, die ja nur ein Objekt neu zeichnet. In unserem Falle ist dies die G_box, in der sich ja der einzublendende Teil befindet. Somit wird der ganze Boxinhalt der G_box neu gezeichnet und siehe da, der verschollene Teil der Dialogbox erscheint auf dem Bildschirm.
Nun wird man sich sicherlich fragen, wie man denn so ein Teil der Dialogbox verschwinden läßt. Im Prinzip ganz einfach, man setzt das sogenannte HIDETREE-Flag für das auszublendende Objekt (in unserem Falle TXT). Doch dazu kann man dann gleich mehr in der Beschreibung der Hide-Routine nachlesen.
In der Unhide-Routine findet man gleich eine ganze Reihe unserer neu vorgestellten Routinen wieder. Zunächst wird das HIDETREE-Flag (&H80) gelöscht und anschließend das Objektflag mit dem Wert &H200 überprüft. Wie wir aus Tabelle 2 erkennen können, ist dies ein unbenutztes Flag, das wir hier dazu benutzen. um uns merken, ob ein editierbares Feld (EDITABLE-Flag) vorhanden war. War deswegen, da dies ja nur funktionieren kann, wenn das Merk-Flag zuvor schon gesetzt ist. Da dies im RCS leider nicht möglch ist, klappt es nur von Hand, d.h. man muß es selbst mit der Set_flag-Routine setzen. Ist der Boxteil also schon im RCS „gehidet“ worden, muß das Merk-Flag gleich nach dem Rsrc_gaddr-Aufruf gesetzt werden. Wird allerdings erst im Programm ausgeblendet, wird diese Arbeit automatisch von der Hide-Routine übernommen.
Hide_but Selectable, Radio Butn, Touchexit
Unhide_b Selectable, Radio Butn, Touchexit
Abbruch Selectable, Default, Exit
Nun stellt sich die Frage, warum wir uns merken wollen, daß ein editierbares Feld vorhanden war. Ganz einfach! Läßt man einen Boxteil verschwinden, in dem so ein Feld existiert, bleibt auf dem Bildschirm an dieser Stelle ein hübscher, schmaler Strich stehen. Bei näherer Untersuchung mit den Cursortasten stellt sich dann heraus, daß dies der Cursor ist. Er bleibt uns also erhalten, während der Rest rundherum unsichtbar wird. Um dagegen Abhilfe zu schaffen, müssen wir das EDITABLE-Flag vor dem Objc_update-Aufruf löschen. Allerdings wollen wir uns dieses Löschen merken und setzen deswegen das Merk-Flag.
In unserer Unhide-Routine wird folglich, wenn das Merk-Flag ungleich Null ist (Ret < > Null), das EDITABLE-Flag wieder gesetzt und das Merk-Flag gelöscht. Ist kein editierbares Feld vorhanden, ist der Merk-Flag immer Null, wodurch die Routinen in der If.. Then-Schleife übersprungen werden.
Als Parameter benötigen wir nur die Baumadresse und den Objektindex (in unserem Beispiel TXT).
Hide — Ausblenden eines Teils der Dialogbox
Hide (Baumadresse%, Objektindex%)
Nachdem Sie jetzt schon so viel über die Technik des Ein- und Ausblenden von Boxteilen gehört (eigentlich gelesen) haben, bleibt kaum noch etwas zu sagen.
Das Wichtigste ist wohl, daß man das HIDETREE-Flag bereits im RCS setzen kann. Dazu klickt man einfach das Objekt (in unserem Falle TXT), das verschwinden soll, an (selektieren), worauf es sich invertiert. Anschließend braucht man nur noch in der Menüleiste den Punkt Hide anzuwählen und schon ist das Objekt verschwunden. Will man es dagegen wieder sichtbar machen, muß man die Box um das Objekt (EDBOX) selektieren und Un-hide in der Menüleiste anklicken. Soviel zum RCS.
Will man das Objekt erst im eigenen Programm ausblenden, so hilft hierbei unsere Hide-Routine. Sie bildet das genaue Gegenstück zur Unhide-Routine. Folglich wird das HIDETREE-Flag gesetzt und überprüft, ob das Objekt editierbar ist. Ist dies der Fall (Ret < > Null) wird das Merk-Flag (&H200) gesetzt und das EDITABLE-Flag und somit der Cursor gelöscht.
Als Parameter werden wieder die Baumadresse und der Objektindex (in unserem Falle TXT) benötigt.
In dieser Folge finden sich zwei Beispiele für Dialogboxen. Das Erste zeigt eine Anwendung von Radiobuttons. Damit sind Buttons gemeint, die sich gegenseitig ausschalten, genauso wie es bei den meisten Radios geschieht. Beim Aufbau der Dialogbox im RCS muß auch hier eine Box des Typs G_box oder G_ibox benutzt werden. So wird die Abhängigkeit der Buttons voneinander dem AES mitgeteilt. Genau wie bei Hide/Unhide nimmt man hier normalerweise eine G_ibox. Doch zu Demonstrationszwecken haben wir wieder eine sichtbare Box verwendet. Auch in diesem Programm finden ein paar der neuen Routinen Verwendung.
Benutzt werden im ersten Programmbeispiel folgende Routinen: Rsrc_load, Rsrc_gaddr, Do_objc, Box_draw, Form_do, Box_undraw, Is_objc, Rsrc_free, Form_center, Form_dial und Objc_draw.
Nach den obligatorischen Aufrufen von Rsrc_load und Rsrc_gaddr selektieren wir zunächst den Button A mit der Do_objc-Routine vor, um damit zu bezwecken, daß beim Zeichnen der Dialogbox bereits ein Button (nämlich Button A) invertiert und somit vorselektiert ist. Auch die Aufrufe Box_draw, Form_do und Box_undraw kennen wir bereits aus der letzten Folge, so daß sie hier nicht weiter erklärt werden. Die Routine Undo_objc kam in der letzten Ausgabe zwar schon vor, wurde aber erst diesmal erklärt. Sie wird hier zum Deselektieren des Exit-Buttons (Ex_obj%=Ok) benutzt. Feider müssen wir anschließend mit drei If.. Then-Abfragen überprüfen, welcher Button nach dem Verlassen der Form_do-Routine selektiert ist, da es in GFA-BASIC keine CASE-Anweisung gibt (vielleicht ändert sich das ja mal in einer neueren Version). Nicht zu vergessen ist am Ende des Programmes der Rsrc_free-Aufruf.
Benutzt werden im zweiten Programmbeispiel folgende Routinen: Rsrc_load, Rsrc_gaddr, Ptadr, Do_objc, Box_draw, Form_do, Box_undraw, Is_objc, Hide, Unhide, Objc_update, Get_dialogtext, Undo_objc, Rsrc_free, Form_center, Form_dial, Objc_draw, Set_flag, Del_flag, Is_flag, Get_objc_xywh und Objc_offset.
Im zweiten Programm sind ebenfalls Radiobuttons enthalten. Die Buttons Hide und Unhide schalten sich also gegenseitig aus bzw. deselektieren sich gegeneinander. Zuvor wird nach dem üblichen Vorgehen (Rsrc__load und Rsrc_gaddr) noch die Textadresse des Edit-Feldes ermittelt, was ja schon in der letzten Ausgabe erklärt wurde, und der Unhide-Button vorselektiert, da das FQDETREE-Flag im RCS nicht gesetzt wurde (also Unhide vorliegt).
Nun kommt der eigentliche Punkt, der das Ein- und Ausblenden von Dialogboxteilen erst erlaubt. Die beiden Radiobuttons Hide und Unhide müssen zuvor im RCS als TOUCHEXIT erklärt worden sein. Vergißt man dies, passiert auf den Bildschirm nicht allzu viel, wenn man die Buttons anklickt. Schön, sie schalten sich gegenseitig aus, aber von Ein- und Ausblenden kann keine Rede sein. Es ist also wichtig, daß die TOUCHEXIT-Flags gesetzt sind. Das erklärt sich dadurch, daß das Programm ansonsten in der Form_do-Routine hängt, die ja bekanntlich in einer Schleife läuft, bis man ein Objekt, das zuvor EXIT, DEFAULT oder TOUCHEXIT erklären wurde, anklickt. Durch das Setzen des TOUCHEXIT-Flags wird die Form_do-Routine verlassen und je nachdem, welcher der beiden Radiobuttons angeklickt wurde, wird das HEDETREE-Flag gesetzt oder gelöscht und anschließend die Box, in der das Edit-Feld liegt (Edbox), mit Objc_update neu gezeichnet. Damit das Programm nicht nach dem ersten Verlassen der Form_do-Routine beendet wird, läuft es in einer Do.. Loop-Schleife, die als Abbruchbedingung nur auf den Abbruch-Button der Dialogbox reagiert (Ex_obj%=Abbruch). Nach Beendigung der Schleife wird der Text aus dem Edit-Feld herausgelesen, die Dialogbox geschlossen und der Abbruch-Button de-selektiert. Letzteres könnte man zwar auch unterlassen, aber die Macht der Gewohnheit zwingt einen manchmal zum sauberen Abschluß eines Programmes. Man könnte genauso gut das „End“ weglassen, was auch nicht üblich ist. Nicht zu vergessen wieder Rsrc_free am Programmende aufzurufen.
Somit sind wir nicht nur am Programmende, sondern auch am Ende dieser Folge angekommen. Wir hoffen, wieder wertvolle Tips gegeben zu haben und würden uns über ein hoffentlich positives Echo freuen. Den Löwenanteil der Routinen, die man zum Handling von Dialogboxen benötigt, haben wir jetzt vorgestellt. Es liegt nun an jedem selbst, was er damit anfängt. Nach unserer Sommerpause (dieses Heft ist ja eine Doppelnummer) melden wir uns dann Ende August wieder mit neuen Anwendungsbeispielen und natürlich auch neuen Routinen.
(HE)
' ********************************
' * *
' * Dialogboxen in GFA-BASIC *
' * *
' * Teil II (Radiobuttons) *
' * HE *
' * *
' ********************************
Baum=0 ! TREE
A_button=2 ! OBJECT in TREE #0
B_button= 3 ! OBJECT in TREE #0
C_button=4 ! OBJECT in TREE #0
Ok=7 ! OBJECT in TREE #0
'
Gosub Rsrc_load("juli871.rsc",*Fehler%)
If Fehler%=0 Then
Print "RSC-Ladefehler"
End
Endif
'
Gtype%=0
Gindex%=Baum
Gosub Rsrc_gaddr(Gtype%,Gindex%,*Baum_adr)
'
Gosub Do_objc(Baum_adr,A_button,1)
Gosub Box_draw(Baum_adr,0,0,0,0)
Gosub Form_do<Baum_adr,Datum,*Ex_obj%)
Gosub Box_undraw(Baum_adr,0,0,0,0)
Gosub Undo_objc(Baum_adr,Ex_obj%,1)
Gosub Is_objc(Baum_adr,A_button,1,*Status%)
If Status%=1 Then
Print "Button A wurde ausgewählt !"
Endif
Gosub Is_objc(Baum_adr,B_button,1,*Status%)
If Status%=1 Then
Print "Button B wurde ausgewählt !"
Endif
Gosub Is_objc(Baum_adr,C_button,1,*Status%)
If Status%=1 Then
Print "Button C wurde ausgewählt !"
Endif
'
Gosub Rsrc_free
End
' ********************************
' * *
' * Dialogboxen in GFA-BASIC *
' * *
' * Teil II (Hidetree *
' * & Touchexit) HE *
' * *
' ********************************
Baum=0 ! TREE
Edbox= 1 ! OBJECT in TREE #0
Txt = 2 ! OBJECT in TREE #0
Abbruch=3 ! OBJECT in TREE #0
Hide_but=6 ! OBJECT in TREE #0
Unhide_b = 7 ! OBJECT in TREE #0
'
Gosub Rsrc_load("juli872.rsc",*Fehler%)
If Fehler%=0 Then
Print "RSC-Ladefehler"
End
Endif
'
Gtype%=0
Gindex% = Baum
Gosub Rsrc_gaddr(Gtype%,Gindex%,*Baum_adr)
Obj_index%=Txt
Flag%=1 ! Cursor zurücksetzen
Gosub Ptadr(Baum_adr,Obj_index%,Flag%,*Txt_adr%)
'
Gosub Do_objc(Baum_adr,Unhide_b,1)
Rette%=1 ! Hintergrund retten
Gosub Box_draw(Baum_adr,0,0,0,0)
Rette%=0 ! keinen Hintergrund retten
Do
Gosub Form_do(Baum_adr,Datum,*Ex_obj%)
Exit If Ex_obj%=Abbruch
Gosub Is_objc(Baum_adr,Hide_but,1,*Status%)
If Status%=1 Then
Gosub Hide(Baum_adr,Txt)
Gosub Objc_update(Baum_adr,Edbox)
Print "Hide-Flag gesetzt !"
Else
Gosub Unhide(Baum_adr,Txt)
Gosub Objc_update(Baum_adr,Edbox)
Print "Hide-Flag gelöscht !"
Endif
Loop
'
Gosub Get_dialogtext(Txt_adr%,*Txt$)
Print "Der Text lautet : ";Txt$
Gosub Box_undraw(Baum_adr,0,0,0,0)
Gosub Undo_objc(Baum_adr,Ex_obj%,1)
Gosub Rsrc_free
End
Procedure Objc_draw(Tree%,Startob%,Depth%,Xclip%,Yclip%,Wclip%,Hclip%)
'
If Rette%=1 Then
Get Xclip%,Yclip%,Xclip%+Wclip%+1,Yclip%+Hclip%+1,Rette%
Endif
Dpoke Gintin,Startob%
Dpoke Gintin+2,Depth%
Dpoke Gintin+4,Xclip%
Dpoke Gintin+6,Yclip%
Dpoke Gintin+8,Wclip%
Dpoke Gintin+10,Hclip%
Lpoke Addrin,Tree%
Gemsys 42
Aes_return%=Dpeek(Gintout) ! Fehlerabfrage
Return
'
Procedure Do_objc(Tree%,Obj_index%,Bit%)
'
Obj_adresse%=Tree%+24*Obj_index%
Aus=Dpeek(Obj_adresse%+10)
Dpoke Obj_adresse%+10,Aus Or Bit%
Return
'
Procedure Undo_objc(Tree%,Obj_index%,Bit%)
'
Obj_adresse% = Tree% + 24*Obj_Index%
Aus=Dpeek(Obj_adresse%+10)
Dpoke Obj_adresse% +10,Aus And Not Bit%
Return
'
Procedure Is_objc(Tree%,Obj_index%,Bit%,Aes_return%)
'
Obj_adresse% = Tree%+24*Obj_index%
Aus = Dpeek(Obj_adresse%+10)
*Aes_return%=Aus And Bit%
Return
'
Procedure Set_flag(Tree%,Obj_index%,Bit%)
'
Obj_adresse%=Tree%+24*Obj_index%
X=Dpeek(Obj_adresse%+8)
Dpoke Obj_adresse%+8,X Or Bit%
Return
'
Procedure Del_flag(Tree%,Obj_index%,Bit%)
'
Obj_adresse% = Tree%+24*Obj_index%
X=Dpeek(Obj_adresse%+8)
Dpoke Obj_adresse%+8,X And Not Bit%
Return
'
Procedure Is_flag(Tree%,Obj_index%,Bit%,Aes_return%)
'
Obj_adresse%=Tree%+24*Obj_Index%
Ret = Dpeek(Obj_adresse%+8)
*Aes_return%=Ret And Bit%
Return
'
Procedure Objc_offset(Tree%,Obj_index%,X%,Y%)
'
Dpoke Gintin,Obj_index%
Lpoke Addrin,Tree%
Gemsys 44
Aes_return% = Dpeek(Gintout) !Fehlerabfrage
*X% = Dpeek(Gintout+2)
*Y% = Dpeek(Gintout+4)
Return
'
Procedure Get_objc_xywh(Tree%,Obj_index%,X%,Y%,Width%,Height%)
'
Gosub Objc_offset(Tree%,Obj_index%,*X,*Y)
*X% = X
*Y% = Y
Obj_adresse% = Tree%+24*Obj_index%
*Width%= Dpeek(Obj_adresse%+20)
*Height%=Dpeek(Obj_adresse%+22)
Return
'
Procedure Objc_update(Tree%,Obj_index%)
'
Gosub Get_objc_xywh(Tree%,Obj_index%,*X,*Y,*W,*H)
Gosub Objc_draw(Tree%,Obj_index%,8,X,Y,W,H)
Return
'
Procedure Unhide(Tree%,Obj_index%)
'
Gosub Del_flag(Tree%,Obj_index%,&H80) ! Unhide
Gosub Is_flag(Tree%,Obj_index%,&H200,*Ret) ! Merker ?
If Ret<>0 Then
Gosub Set_flag(Tree%,Obj_index%,8) ! Editable
Gosub Del_flag(Tree%,Obj_index%,&H200) ! Merker löschen
Endif
Return
'
Procedure Hide(Tree%,Obj_index%)
Gosub Set_flag(Tree%,Obj_index%,&H80) ! Hide
Gosub Is_flag(Tree%,Obj_index%,8,*Ret)! Editable ?
If Ret<>0 Then
Gosub Set_flag(Tree%,Obj_index%,&H200) ! Merker
Gosub Del_flag(Tree%,Obj_index%,8) ! Editable löschen
Endif
Return