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
Aus: ST-Computer 05 / 1989, Seite 73

Links

Copyright-Bestimmungen: siehe Über diese Seite