Dialogboxen in GFA-BASIC Teil III

Wie versprochen, gibt es in dieser (übrigens vorletzten) Folge wieder neue Anwendungsbeispiele und Prozeduren zur leichten Handhabung von Dialogboxen. Wir wenden uns diesmal der Programmierung eines Schiebereglers und eines neuen Desktops (auch ein Desktop ist im Grunde eine Dialogbox) zu.

Doch zunächst ein Wort in eigener Sache. Für Leser, die neu zu diesem kleinen Kurs hinzukommen, sei unbedingt empfohlen, die beiden ersten Folgen zu studieren und mit den dort vorgestellten Routinen zu experimentieren, da diese ebenso wie der Umgang mit einem Resource-Construction-Set als bekannt vorausgesetzt werden.

Da wir mit Beendigung des letzten Teils im Juli/August-Heft den Löwenanteil der notwendigen Prozeduren bereits hinter uns haben, wollen wir jetzt nur noch spezielle Beispiele mit den eventuell zu ergänzenden Prozeduren vorstellen.

Neue Prozeduren

Graf_slidebox - Verschieben eines Rechtecks in einem anderen Rechteck

Graf_slidebox(Baumadresse%, Außenrechteck%, Schieber%, Richtung%, * Position%)

Mit Graf_slidebox haben wir wieder einmal eine Original-AES-Routine (Gemsys 76) vor uns. Sie dient dazu, ein Rechteck, also eine Box, innerhalb einer anderen Box zu verschieben, solange eine Maustaste gedrückt bleibt. Hierfür wird eine ganze Reihe von Parametern benötigt. Zunächst wieder einmal die obligatorische Baumadresse im Speicher. Anschließend werden die Objektindizes der beiden Boxen übergeben (oben Außenrechteck% für die Außere und Schieber für die Innere genannt). Ferner ermöglicht Graf_slidebox eine Bewegung der inneren Box in horizontaler oder vertikaler Richtung. Wir haben einen horizontalen Schieberegler gewählt und mußten deswegen eine Null als Parameter übergeben. Für die vertikale Richtung dient eine Eins. Zurückgegeben wird von der Routine die relative Position des Mittelpunkts unseres Schiebers (X-Posi-tion bei horizontaler und Y-Position bei vertikaler Bewegung). Relativ deshalb, weil man einen Wert zwischen 0 und 1000 erhält, den man erst in das richtige Verhältnis setzen muß. Man nimmt dazu die Breite der inneren Box und subtrahiert sie von der der äußeren Box. Anschließend multipliziert man das Ergebnis mit dem Rückgabewert und dividiert das Ganze durch 1000. Daraus ergibt sich dann folgende Formel zur Berechnung:

Ergebnis = (Außenbreite - Innenbreite) * Rückgabewert / 1000

Die gleiche Formel wird übrigens zur Berechnung der verschiebbaren Balken bei der Fensterprogrammierung benutzt.

Procedure Graf_slidebox(Gr_sltree%,Gr_s1parent%,Gr_s1ob%, Gr_slvh%,Aes_return)
	'
	Dpoke Gintin,Gr_slparent%
	Dpoke Gintin+2,Gr_slob% 
	Dpoke Gintin+4,Gr_slvh%
	Lpoke Addrin,Gr_sltree%
	Gemsys 76
	*Aes_return = Dpeek(Gintout)
Return

Procedure Set_xrel(Tree%, Obj_index%, Xrel%)
	'
	Obj_adresse%=Tree%+24*Obj_index%
	Dpoke Obj_adresse%+16,Xrel%
Return

Listing 3

Set_string: Schreibt einen String in eine Dialogbox

Set_string (Baumadresse%, Objektindex%, String$, Stringlänge)

Diese Routine ändert einen in einer Dialogbox definierten String. Benötigt werden zunächst die Baumadresse und der Objektindex. Mit ihnen läßt sich die Adresse des Strings mittels ob_spec (Lpeek auf die Objektadresse plus 12) ermitteln. Der nächste Schritt dient dazu, den String auf die richtige Länge zu bringen. Hierfür sind die Parameter StringS und Stringlänge erforderlich. In einer While...Wend-Schleife wird solange eine Leerstelle vor den eigentlichen String gehängt, bis er die in der Stringlänge definierte Länge hat, im günstigsten Fall also gar keine. Anschließend wird der neue String einfach Zeichen für Zeichen an die er-rechnete Adresse geschrieben.

Procedure Set_string(Tree%,Obj_index%,Str_txt$,Laenge%)
	'
	Obj_adresse%=Tree%+24*Obj_index%
	Str_adresse%=Lpeek(Obj_adresse%+12)
	While Len(Str_txt$)<>Laenge%
		Str_txt$ = " "+Str_txt$
	Wend
	For I%=0 To Laenge%-1
		Poke Str_adresse%+I%,Asc(Mid$(Str_txt$,I%+1,1))
	Next I%
Return

Listing 7:

Set_xrel: Setzt relative X-Koordinate eines Objektes neu

Set_xrel (Baumadresse%, Objektindex%, X-Koordinate%)

Diese Routine ist die vereinfachte Form einer Prozedur, die wir gleich anschließend vorstellen wollen. Deswegen wird hier nicht näher darauf eingegangen. Will man einen Schieberegler in vertikaler Richtung bewegen, muß man natürlich die relative Y-Koordinate statt der X-Koordinate setzen (Objektadresse%+ 18,Yrel%).

Put_objc_xywh: Setzt die relativen X-, Y-Koordinaten, Breite und Höhe eines Objektes

Put_objc_xywh(Baumadresse%, Objektindex%, X%, Y%, Breite%, Höhe%)

Nun also die vollständige Version, die alle Maße eines Objektes bestimmen kann. Die Routine bildet praktisch das Gegenstück zur Prozedur Get_objc_xvwh, die wir ja bereits in der letzten Folge kennengelernt haben. In unserem Beispiel benutzen wir sie, um ein neues Desktop zu kreieren bzw. eine Dialogbox auf die richtige Größe zu bringen. Dies ist leider notwendig, da das RCS nicht in der Lage ist, so große Dialogboxen zu erstellen. Die Parameter erfordern wohl keine besondere Erklärung.

Procedure Put_objc_xywh(Tree%,Obj_index,X,Y,Width,Height)
	'
	Obj_adresse%=Tree%+24*Obj_index 
	Dpoke Obj_adresse%+16,X 
	Dpoke Obj_adresse%+18,Y 
	Dpoke Obj_adresse%+20,Width
	Dpoke Obj_adresse%+22,Height
Return

Listing 4

Wind_get: Ermittelt Werte von Fensterkomponenten

Wind_get (Windowhandle%, Feld%,*X%, *Y%, *Breite%, *Höhe%)

Die AES-Routine Wind_get (Gemsys 104) ist recht universell. Sie kommt, wie der Name vermuten läßt, aus der Fensterprogrammierung. Wir wollen uns hier jedoch auf unsere spezielle Anwendung beschränken. Man muß nur soviel wissen, daß die Daten über jedes Fenster in einer sogenannten Rechteckliste vorhanden sind. Jedes Fenster besitzt eine solche Liste. Durch den ersten Parameter Windowhandle% wird bestimmt, welches Fenster angesprochen wird. Wir müssen in unserem Falle eine Null übergeben, da für einen Desktop immer das Window-handle% Null reserviert ist. Was nun Wind_get aus dieser oben erwähnten Rechteckliste holt, hängt von dem Parameter Feld% ab. Wir übergeben in unserem Beispiel eine Vier, die bewirkt, daß die Koordinaten des gesamten Arbeitsbereiches eines Fenster bzw. des Desktops zurückgegeben werden. Arbeitsbereich bedeutet bei einem Desktop der gesamte Bildschirm bis auf die Menüleiste, die ausgespart bleibt. Will man den ganzen Bildschirm ohne Menüleiste benutzen, was wohl nicht im Sinne von GEM wäre, müßte man als Parameter eine Fünf übergeben. Alle weiteren Möglichkeiten sind für uns momentan uninteressant und würden zu sehr in die Fensterprogrammierung führen.

Procedure Wind_get(Handle%,Fie1d%,Wi_gw1%,Wi_gw2%,Wi_gw3%,Wi_gw4%)
	'
	Dpoke Gintin,Handle%
	Dpoke Gintin+2,Field%
	Gemsys 104
	*Wi_gw1%=Dpeek(Gintout+2)
	*Wi_gw2%=Dpeek(Gintout+4)
	*Wi_gw3%=Dpeek(Gintout+6)
	*Wi_gw4%=Dpeek(Gintout+8)
	Fehler%=Dpeek(Gintout)
Return

Listing 5:

Wind_set: Setzt Werte von Fensterkomponenten

Wind_set (Windowhandle%, Feld%, Baumadresse%)

Wind_set (Gemsys 105) bildet quasi das Gegenstück zu Wind_get. Normalerweise kann man wieder vier Parameter neben Windowhandle% und Feld% angeben. Das hätte aber bei der Desktop-Programmierung zur Folge, daß die Baumadresse% auf zwei Parameter verteilt würde, also in High-und Low-Word aufgespalten werden müßte. Man hätte sich natürlich auch für diesen Fall eine Routine schreiben können, aber da wir hier keine Fenster programmieren wollen, haben wir darauf verzichtet. Man muß nur darauf achten, diese Routine gegebenenfalls zu modifizieren, damit sie dann universell ist.

Zu den Parametern ist zu sagen, daß wieder das Windowhandle% (also beim Desktop eine Null) zu übergeben ist. Der Feld%-Parameter erhält den Wert 14, was dem AES mitteilt, daß ein neuer Desktop angemeldet wird. Anschließend muß nur noch die Baumadresse des neuen Desktops angegeben werden.

Procedure Wind_set(Handle%,Field%,Wi_sw1%)
	'
	Dpoke Gintin,Handle% 
	Dpoke Gintin+2,Fie1d% 
	Lpoke Gintin+4,Wi_sw1%
	Gemsys 105
	Fehler%=Dpeek(Gintout)
Return

Listing 6:

Ein Schieberegler im GEM-Gewand

Das eigentlich Schwierige beim „Bauen“ eines Schiebereglers ist das Ge-wußt-wie. Wenn man erst einmal die nötigen „Bauelemente“ hat, ist es eine reine Konstruktionssache mit dem RCS. Auf Bild 1 erkennen Sie, daß der reine Schieber nur aus Elementen des Typs G_box besteht, die ineinander verschachtelt werden. Zur besseren Unterscheidung der einzelnen Boxen haben wir verschiedene Füllmuster ausgewählt. Es ist auch darauf zu achten, das die äußere Box des Schiebers (Daddy) das übergeordnete Objekt zur inneren Box (Slider) ist.

Wichtig ist dabei, daß der eigentliche Schieber, also die innere Box, im Bild Slider genannt, bei der Erstellung als TOUCHEXIT (das TOUCHEXIT-Flag setzen) erklärt wird. Würden wir dies unterlassen, könnten wir unsere Dialogbox nur über den Weiter-Button verlassen und unser Schieber ließe sich nicht eine Spur bewegen.

Wegen wiederholter Anfragen noch einmal kurz zum Erstellen der Dialogboxen und zu den Bildern: Die Objekte der Dialogbox sind in Klammern geschrieben. Ist es notwendig, daß ein Objekt mit einem Namen versehen wird, steht dieser Name kursiv vor dem Objekt. Soweit zum Format der Bilder.

Benutzt werden im ersten Programmbeispiel folgende Routinen:

Rsrc_load, Rsrc_gaddr, Box_draw, Form_do, Form_center, Form_dial, Objc_draw, Rsrc_free, Box_undraw, Get_objc_xywh, Objc_update, Objc_offset, Graf_slidebox, Set_String, und Set_xrel.

Obligatorisch sind wie immer die Prozeduren Rsrc_load, Rsrc_gaddr und Box_draw, so daß diese hier nicht mehr weiter besprochen werden sollen. Doch dann wird es schon interessanter. Als erstes benötigen wir die Breiten des Schiebers und der Box um den Schieber, um damit später mit der oben angegebenen Formel den Rückgabewert von Graf_slidebox richtig zu berechnen. Dies erreichen wir durch die Aufrufe der Prozedur Get_objc_xywh.

Das Ergebnis wird der Variablen Pos_alt zugewiesen. Ferner wird als Bewegungsrichtung horizontal ausgewählt.

Nun kommen wir zur Do...Loop-Schleife. Sie wird erst dann verlassen, wenn der weiter-Button (Ok) angeklickt wird. Klickt man also auf den Schieber der Box, bleibt man immer noch in der Schleife. Dadurch wird es uns ermöglicht, den Regler überhaupt zu verschieben, da durch Anklicken des TOUCHEXIT erklärten Schiebers die Form_do-Routine verlassen wird und die übrigen Prozeduren erst angesprochen werden können. Durch Graf_slidebox erhält man die Möglichkeit, den Schieber zu bewegen, solange ein Mausknopf gedrückt bleibt. Läßt man ihn los, wird der Schieber an die Stelle positioniert, an der man losgelassen hat. Dazu dienen die Routinen Set_xrel, mit der die neue relative X-Position in die Objektstruktur geschrieben, und Objc_update, mit der der Inhalt der äußeren Box (Daddy) neu gezeichnet wird. Zuvor werden der neue X-Wert nach der oben erwähnten Formel berechnet, der Original-Rückgabewert und der berechnete Wert mittels Set_string in die Box geschrieben und die Box um diese beiden Strings neu gezeichnet. Am Ende kommen dann wieder die gewohnten Routinen Box_undraw, Undo_objc und Rsrc_free.

Ein eigener Desktop

Viele mögen sich hier vielleicht fragen, wozu ein eigener Desktop überhaupt notwendig sei. Er bringt einen wesentlichen Vorteil mit sich: Der sogenannte Screenmanager (Bildschirmverwalter) nimmt unseren neuen Desktop unter seine Fittiche. Das heißt zum Beispiel, daß alle Objekte, die in unserem Desktop integriert sind, automatisch neu gezeichnet werden, falls sie durch irgendeine Box oder ein Fenster überlagert waren. Das dürfte im häufigsten Falle bei Icons (z. B. Laufwerk-Icons) oder Funktionstasten la 1st_Word auftreten. Kurz gesagt, wir brauchen uns nicht mehr um das Retten des Hintergrunds zu kümmern. Aber dies trifft nur bei Objekten zu, die in unserem Desktop integriert sind, die also schon in unserer Dialogbox vorhanden sind, wenn sie als Desktop angemeldet wird, nicht bei nachträglich auf den Desktop gezeichneten Objekten. Wir haben als Beispiel ein sogenanntes Image in den Desktop eingebaut, das zuvor mit einem Icon-Editor erstellt wurde. Doch nun zur Programmierung.

' *******************************
' *                             *
' *   Dialogboxen in GFA-BASIC  *
' *                             *
' *  Teil III (Schieberegler)   *
' *                        HE   *
' *                             *
' *******************************
'
Baum=0		! TREE
Daddy = 2	! OBJECT in TREE #0
S1ider = 4	! OBJECT in TREE #0
Ok=9		! OBJECT in TREE #0
Werte = 12	! OBJECT in TREE #0
Slide w=13	! OBJECT in TREE #0
Calc_w =14	! OBJECT in TREE #0
'
Gosub Rsrc_load("sept871.rsc",*Fehler%)
If Fehler% = 0 Then
	Print "RSC-Ladefehler"
	End 
Endif
'
Gtype%=0 
Gindex%=Baum
Gosub Rsrc_gaddr(Gtype%,Gindex%,*Baum_adr)
'
Rette = 1
Gosub Box_draw(Baum_adr,0,0,0,0)
Rette =0
Gosub Get_objc_xywh(Baum_adr,S1ider,*X,*Y,*W,*H)
Gosub Get_objc_xywh(Baum_adr,Daddy,*Xp,*Yp,*Wp,*Hp) 
Hor=0 ! horizontale Bewegung 
Pos_a1t=Wp-W 
Do
	Exit If Ex_obj%=Ok
	Gosub Form_do(Baum_adr,0,*Ex_obj%)
	Gosub Graf_slidebox(Baum_adr,Daddy,S1ider,Hor,*Pos) 
	Pos$=Str$(Pos)
	Gosub Set_string(Baum_adr,S1ide_w,Pos$,4)
	Pos_calc=(Pos_alt)*Pos/1000 
	Pos_calc$=Str$(Int(Pos_ca1c))
	Gosub Set_string(Baum_adr,Calc_w,Pos_calc$,4)
	Gosub Objc_update(Baum_adr,Werte)
	Gosub Set_xrel(Baum_adr,Slider,Pos_calc)
	Gosub Objc_update(Baum_adr,Daddy)
Loop
Gosub Box_undraw(Baum_adr,0,0,0,0)
Gosub Undo_objc(Baum_adr,Ex_obj%,1)
'
Gosub Rsrc_free 
End

Listing 1:

Benutzt werden im zweiten Programmbeispiel folgende Routinen: Rsrc_load, Rsrc_gaddr,Objc_draw, Rsrc_free, Put_objc_xywh, Wind_set und Wind_get.

Nach Rsrc_load und Rsrc_gaddr wird zunächst die Größe des Bildschirms bestimmt, hier für einen monochromen Bildschirm 600x400 Pixel. Will man einen Farbschirm benutzen, müssen hier andere Werte entsprechend der Auflösung eingetragen werden, oder man fragt die Auflösung mittels Xbios(4) ab und setzt die entsprechenden Werte dann ein. Mit Put_objc_xywh werden die Werte in die Objektstruktur geschrieben. Die Koordinaten des Arbeitsbereiches für unseren Desktop holen wir uns anschließend über Wind_get. Die Prozedur meldet dann den neuen Desktop an und mit Objc_draw wird er auf den Bildschirm gebracht. Jetzt kann irgendein Programm folgen, bevor mit Rsrc_free der Speicher wieder freigegeben wird.

Somit genug für diesmal. Im Oktoberheft werden wir uns, im letzten Teil dieser Reihe, mit zwei weiteren Beispielen beschäftigen, die aber jetzt noch nicht verraten werden. Bis dann!

(HE)

' ********************************
' *                              *
' *    Dialogboxen in GFA-BASIC  *
' *                              *
' *    Teil III Eigener Desktop  *
' *                           HE *
' *                              *
' ********************************
'
Desk = 0	!	TREE
Gosub Rsrc_load("sept872.rsc",*Fehler%)
If Fehler%=0 Then
	Print "RSC-Ladefehler”
	End 
Endif 
Gtype%=0 
Gindex%=Desk
Gosub Rsrc_gaddr(Gtype%,Gindex%,*Baum)
Ob_width=640 
Ob_height=400 
Obj_index=0
Gosub Put_objc_xywh(Baum,Obj_index,0,0,Ob_width,Ob_height) 
Gosub Wind_get(0,4,*Xdesk%,*Ydesk%,*Wdesk%,*Hdesk%)
Gosub W:nd_set(0,14,Baum)
Gosub Objc_draw(Baum,0,8,Xdesk%,Ydesk%,Wdesk%,Hdesk%)
Alert 1,"Dies ist ein eigener Desktop! |    in GFA-BASIC !!",1,"weiter",A
Gosub Rsrc_free
End

Listing 2:



Aus: ST-Computer 09 / 1987, Seite 24

Links

Copyright-Bestimmungen: siehe Über diese Seite