Die schnelle Dialogbox (Modula-2)

Ist Ihnen schon einmal aufgefallen, wie langsam manche Programme ihre Fenster erneuern, wenn eine Dialogbox geschlossen wurde? Die hier vorgestellte Routine erneuert den Bildschirm selbst, womit die Wartezeiten erheblich verkürzt werden.

Vorab sei gesagt, daß das (Megamax Modula 2-) Listing zwar zu einem ablauffähigen Programm übersetzt werden kann, aber es erfüllt keinen sinnvollen Zweck. Wichtig ist vielmehr die Routine DoDialog, die einen vollständigen Dialog durchführt.

Ein normaler Ablauf zur Darstellung und Durchführung eines Dialogs sieht grob wie folgt aus:
Dialogbox zentrieren mit FORM CENTER (AES 54),
Reservierung eines Bildschirmbereichs mit FORM_DIAL (AES 51) - FMD_START -,
Darstellung der Dialogbox mit OBJC_DRAW (AES 42),
Durchführung des Dialogs mit FORM_DO (AES 50),
Freigeben des reservierten Bildschirmbereichs mit FORM_DIAL (AES 51) - FMD_FINISH -.

Aber gerade der Aufruf von FORM_DIAL kostet Zeit. Wird nämlich der zuvor reservierte Bildschirmbereich freigegeben, so erhalten alle Programme, die Fenster geöffnet haben und in dem Bildschirmbereich liegen, die Meldung, die Fenster zu erneuern. Selbst der Desktop braucht eine halbe Ewigkeit. Abhilfe kann nur geschaffen werden, wenn man selbst für den Bildschirmwiederaufbau sorgt. Die Alertboxen und Menüs gehen mit gutem Beispiel voran, allerdings beschränkt sich die Größe des Rechtecks, welches erneuert werden soll, auf 25% der vollen Bildschirmgröße. Dialogboxen sind aber selten größer!

Die Routine DoDialog ersetzt die beiden FORM_DIAL-Aufrufe. Hierzu wird vor Aufruf der Routine ein Speicherbereich von ca. 32 kB reserviert. Den Bildschirmbereich, den die Dialogbox einnehmen wird, kopiert man in den reservierten Speicherbereich und stellt dann die Dialogbox dar. Nach Beendigung des Dialoges wird einfach der kopierte Bildschirmbereich zurückgeholt. Zum Kopieren der Bildschirmbereiche wird COPY RASTER, OPAQUE (VDI 109) verwandt. Bei der Reservierung des Speicherbereichs ist darauf zu achten, daß die Speicheradresse auf eine durch 512 teilbare Bytezahl fällt, sonst klappt nichts.

Sollte der Speicherplatz nicht reichen, wird dennoch die alte FORM_DIAL-Routine benutzt. Es könnte ja sonst passieren, daß sich die Dialogbox gar nicht mehr darstellen läßt.

Das Programm um die Routine DoDialog herum stellt ein Accessory dar. Die Dialogbox ist vorher mit einem Resource-Construction-Programm anzulegen.

Mit diesem Accessory läßt sich hervorragend die Zeit messen, die benötigt wird, um Fenster neu aufzubauen. Bei einem kleinen Test mit dem TOS vom 6.2.’86 - also ohne Blitter - dauerte die Fensterrestaurierung nach dem Öffnen einer normalen Dialogbox gut 2 Sekunden (diese Zeit läßt sich prima mit einer Stoppuhr messen!), unsere Demo-Dialogbox war so schnell, daß man die Zeit nicht einmal nehmen konnte. Benutzt wurden die fünf Fenster, die auch auf dem Bild zu sehen sind.

IMPLEMENTATION MODULE Demodial; 
(*$N+,M-*)
END Demodial.
DEFINITION MODULE Demodial;

EXPORT
    Dialog, Okbutton;

CONST
    Dialog      = 0;    (* Formular/Dialog *)
    Okbutton    = 2;    (* BUTTON in Baum DIALOG *)

END Demodial.

(************************************************) (* Dialogboxdarstellung mit eigener *) (* Bildschirmrestaurierung, 1.00 *) (* ============================================ *) (* Autor: D. Rabich, Dülmen *) (* Entwickelt mit Megamax Modula 2.) *) (************************************************) MODULE FastDial; (*$R-,M-,Q+,N-,V-,P-,S-*) (* Resourcefile *) IMPORT Demodial; (* AES-Routinen *) FROM AESEvents IMPORT MessageEvent,MessageBuffer,accOpen; FROM AESForms IMPORT FormDo,FormDial,FormAlert,FormCenter,FormDialMode; FROM AESGraphics IMPORT MouseForm,GrafMouse; FROM AESMenus IMPORT RegisterAcc; FROM AESObjects IMPORT ChangeObjState,DrawObject,ObjectOffset; FROM AESResources IMPORT LoadResource,ResourceAddr,ResourcePart; FROM AESWindows IMPORT UpdateWindow; FROM ObjHandler IMPORT ObjectState,ObjectSpace; (* allgemeine GEM-Routinen *) FROM GEMEnv IMPORT RC,InitGem,DeviceHandle,GemError; FROM GEMGlobals IMPORT PtrObjTree,ObjState,OStateSet,Root,MaxDepth; (* Graphik *) FROM GrafBase IMPORT Rectangle,Rect,TransRect,Pnt,MemFormDef,GetLogMemForm,BitOperation; (* VDI-Routinen *) FROM VDIRasters IMPORT CopyOpaque; (* sonstige Routinen *) FROM Storage IMPORT ALLOCATE,DEALLOCATE; FROM SYSTEM IMPORT ADR,ADDRESS; VAR Device : DeviceHandle; (* Gerätekenn.*) ReturnButton, (* für Dialog *) VoidC, (* diverse Zwecke *) AccID : CARDINAL; (* Accessory-Kenn.*) DialogBox : PtrObjTree; (* für Dialog *) InitOK : BOOLEAN; (* für Initial. *) Messages : MessageBuffer; (* Puffer für Message *) AccName : ARRAY [0..15] OF CHAR; (* Accessory-Name *) (* führt vollständigen Dialog aus *) PROCEDURE DoDialog (tree : PtrObjTree) : CARDINAL; VAR space : Rectangle; (* Dialogbox-Größe *) Status : OStateSet; (* Object-Status *) button : CARDINAL; (* ausgewähltes Object *) MakeBits : BOOLEAN; (* Flag für reserv. Speicher *) Picture : POINTER TO ARRAY [0..32511] OF CHAR; MemFSource,MemFDest : MemFormDef; (* FDB *) BEGIN UpdateWindow(TRUE); (* k.Fensterausgaben mehr *) space:=FormCenter(tree); (* Dialog zentrieren *) ALLOCATE(Picture,SIZE(PictureA)); (* Platz für Bild *) MakeBits:=Picture#NIL; (* Platz OK? *) IF MakeBits THEN GetLogMemForm(MemFSource); (* FDB holen *) MemFDest:=MemFSource; (* Ziel-FDB *) MemFDest.start:= (* Adresse auf volle 512 Byte *) ADDRESS(LONGCARD(Picture)+512L-(LONGCARD(Picture) MOD 512L)); GrafMouse(mouseOff,NIL); (* Maus aus *) CopyOpaque(Device, (* Hintergrund sichern *) ADR(MemFSource),ADR(MemFDest), space,space,onlyS); GrafMouse(mouseOn,NIL) (* Maus wieder an *) ELSE FormDial(reserveForm,Reet(0,0,0,0),space) (* Bildbereich reservieren *) END; DrawObject(tree,Root,MaxDepth,space); (* Dialog zeichnen *) FormDo(tree,Root,button); (* Dialog durchführ.*) IF MakeBits THEN GrafMouse(mouseOff,NIL); (* Maus aus *) CopyOpaque(Device, (* Hintergrund zurück *) ADR(MemFDest),ADR(MemFSource), space,space,onlyS); GrafMouse(mouseOn,NIL); (* u. wieder Maus an *) DEALLOCATE(Picture,SIZE(Picture^)) (* Speicher freigeben *) ELSE FormDial(freeForm,Reet(0,0,0,0),space); (* Bildbereich freigeben *) END; Status:=ObjectState(button); (* Status angeklicktes Object *) EXCL(Status,selectObj); (* SELECTED entfernen *) ChangeObjState(tree,button, (* neuen Status setzen *) TransRect(ObjectSpace(button), ObjectOffset(tree,button)), Status,FALSE); UpdateWindow(FALSE); (* Fensterausgabe freig. *) RETURN button END DoDialog; BEGIN InitGem (RC,Device,InitOK); (* anmelden *) IF InitOK THEN LoadResource ('DEMODIAL.RSC'); (* Resourcefile laden *) IF GemError() THEN (* OK? *) FormAlert(1,*[0][Das Resourcefile fehlt!][ OK ]',VoidC) ELSE AccName:=' Test...'; (* Accessory-Name setzen *) RegisterAcc(ADR(AccName),AccID,InitOK); (* Accessory anmelden *) IF InitOK THEN (* OK? *) DialogBox:=ResourceAddr(treeRsrc,Dialog); (* Dial.Box-Adr. *) REPEAT MessageEvent(Messages); (* auf Message warten *) IF Messages.msgType=accOpen THEN (* Accessory gefragt? *) ReturnButton:=DoDialog(DialogBox); (* Dialog durchführen *) END; UNTIL FALSE ELSE FormAlert(1,'[0][Accessory|nicht installiert.][ OK ]',VoidC) END END END END FastDial.

Dietmar Rabich
Links

Copyright-Bestimmungen: siehe Über diese Seite