Dialoge in Fenstern verwalten

Auf den Atari ST- und TT-Rechnern hat inzwischen auch das Multitasking Einzug gehalten. Betriebssystemerweiterungen wie MiNT oder MultiGEM erlauben die quasi-parallele Abarbeitung von Programmen.

Das z.B. durch MultiGEM realisierte Multitasking ist ein nicht verdrängendes. Das bedeutet, dem rechnenden Prozeß kann die CPU nicht entzogen werden. Er kann nur unterbrochen werden, wenn er einen GEM- oder einen GEMDOS-Aufruf vornimmt. Alle Bildschirmausgaben müssen in Fenstern stattfinden, sonst kann der Bildschirmaufbau anderer Applikationen zerstört werden (der Inhalt des Fensters wird einfach überschrieben und es wird keine Redraw-Meldung geschickt). Außerdem müssen alle Programme so programmiert sein, daß sie ab und an - vor allem bei längeren Berechnungen ohne GEM-Aufrufe - einen GEM-Aufruf tätigen. Damit können auch andere Applikationen den Prozessor erhalten und mit ihrer Arbeit fortfahren. Sauber unter GEM programmierte Programme können dann quasi-parallel ablaufen. Dies funktioniert auch ganz gut. Nur gibt es da noch die Dialog-, die Alertboxen und die Pull-Down-Menüs. Jedesmal, wenn eines dieser drei Elemente auf dem Bildschirm auftaucht, ist Multitasking nicht mehr möglich. Das Betriebssystem hält die anderen Programme an. Die laufenden Applikationen können solange Weiterarbeiten, bis sie eine Bildschirmausgabe machen wollen; dann müssen sie warten. Das liegt daran, daß z.B. Dialogboxen den erneuten Bildschirmaufbau unterbinden (wind_update). Erfolgte das nicht, hätte das zur Konsequenz, daß der Bildschirmaufbau durcheinander geriete. Es gäbe Bildschirmmüll.

Form_do und Fenster

Um das Multitasking nicht mit Dialogboxen zu behindern, gibt es zwei Möglichkeiten. Erstens: man benutzt keine Dialogboxen. Dies ist nicht unbedingt die beste Möglichkeit.

Zweitens: man schreibt sich eine form_do-Routine, die Dialogboxen in Fenstern verwalten kann. Diese Möglichkeit dürfte die bessere sein, obgleich sie auch einige Schwierigkeiten mit sich bringt. Der Lohn für die Mühen ist, daß andere Programme nicht mehr angehalten werden. Da die Dialogbox in einem Fenster liegt, erübrigt sich der wind_update-Aufruf. Die Gefahr, daß es Probleme bei der Bildschirmausgabe gibt, ist gebannt. Es werden für das Fenster mit der Dialogbox Redraw-Meldungen verschickt. So können die entsprechenden, überlagerten Teile bei Bedarf neu gezeichnet werden.

Ich habe bereits erwähnt, daß die Verwaltung von Dialogboxen in Fenstern gewisse Schwierigkeiten macht. Es ist zu beachten, daß der Text-Cursor in Edit-Feldern ausgeschaltet werden muß. wenn das Fenster überlagert wird. Der Cursor wäre sonst im anderen Fenster zu sehen. Weiterhin muß bedacht werden, daß das im Hintergrund liegende Fenster mit der Dialogbox keine Tastatur- und keine Mausknopfereignisse verarbeiten darf, bis es wieder im Vordergrund liegt.

Listing 1 enthält Auszüge aus einer in MAXON Pascal programmierten Unit, die einige Prozeduren und Funktionen zum Umgang mit Objektbäumen beinhaltet. Aus Platzgründen kann diese Unit nicht ganz abgedruckt werden. Sie befindet sich auf der Monatsdiskette zum Heft. In dieser Unit ist auch die Routine FonnDo implementiert. Kernstück dieser Routine ist, wie auch in der Originalroutine, eine evnt_multi-Schleife. Sie wertet jetzt auch Mitteilungen aus. Wie bisher werden Tastatur- und Mausknopf-Ereignisse bearbeitet. Die Routine benötigt im Gegensatz zur Originalroutine einige Parameter mehr. Es sind das Fenster-Handle und die Applikationsnummer mit zu übergeben. Das Fenster-Handle wird intern gebraucht, um festzustellen, ob das Fenster der Dialogbox oben liegt. Die Applikationsnummer wird benötigt, um Mitteilungen an die eigene Applikation zu schicken. Als Grundlage dient das Listing der form_do-Routine im Atari Profibuch aus dem Sybex-Verlag. Das Listing dort ist in C geschrieben. Es wurde in MAXON Pascal umgesetzt und um einige nützliche Funktionen erweitert. Außer der Verwaltung der Fenster wird die Return- bzw. Enter-Taste ausgewertet. Ist kein Default-Objekt vorhanden, wird durch Drücken der Return-/Enter-Taste in das nächste editierbare Feld gesprungen. Ansonsten wird das Default-Objekt selektiert. Die Tabulator-Taste wird in Cursor Down umgesetzt. Wird zur Tabulator-Taste die Shift-Taste gedrückt, wird die Tabulator-Taste in Cursor Up umgesetzt.

Bild 1: Die Copyright-Meldung
Bild 2: Die Verwaltungs-Maske

Fensterverwaltung

Was die Fensterverwaltung betrifft, werden nur die Mitteilungen WM_UNTOP, WM_ISTOP, WM_MOVED, WM_REDRAW und WM_TOPPED ausgewertet. Die evnt_multi-Schleife in der neuen FormDo-Routine behandelt diese Ereignisse. Die Ereignisse WM_UNTOP und WM_ISTOP sind spezifische Ereignisse von MultiGEM. Sie sind deshalb nur unter MultiGEM verfügbar. WM_UNTOP teilt unserer Applikation mit, daß das gemeldete Fenster nicht mehr das oberste ist. Für uns bedeutet das, daß der Text-Cursor im Edit-Feld ausgeschaltet werden muß. WM_ISTOP teilt uns mit, daß unser Fenster jetzt wieder das aktuelle, oberste ist. WM_REDRAW und WM_MOVED rufen jeweils eine Prozedur auf, die das entsprechende Ereignis verarbeitet. Der Redraw des Fensters geht genauso vor sich wie bei einem normalen Text- oder Grafikfenster. Nur muß hier jeweils ein Teil der Dialogbox neu gezeichnet werden. Dazu wird das Clipping-Rechteck in der objc_draw-Prozedur verwendet. Die Rechteckliste wird wie sonst auch abgearbeitet. Bitte sehen Sie sich das kommentierte Listing zum genauen Vorgehen an. Wird das Fenster bewegt (WM_MO VED), dann wird das Fenster an der entsprechenden Stelle neu gezeichnet. Es wird eine Redraw-Meldung mit appl_write an die eigene Applikation geschickt. Stattdessen kann auch die Redraw-Prozedur direkt aufgerufen werden. Als Startkoordinaten müßten die Koordinaten der Dialogbox übergeben werden. Wird das Fenster verschoben, werden automatisch die neuen Koordinaten in die Objektstruktur eingetragen. Wird vor dem erneuten Öffnen der Dialogbox kein form_center- Aufruf durchgeführt, erscheint die Dialogbox genau an der Stelle, an der sie geschlossen wurde. Man bekommt quasi als Nebeneffekt auf dem Bildschirm verschiebbare Dialogboxen, die sich ihre letzte Position automatisch merken. Der form_center- Aufruf wird beim Ermitteln der Adresse nur einmal am Anfang des Programms vorgenommen. Tastatur- und Mausknopfereignisse dürfen nur verarbeitet werden, wenn unser Fenster mit der Dialogbox das oberste ist. Dazu wird das oberste Fenster mit wind_get bei jedem Ereignis ermittelt und mit dem übergebenen Fenster-Handle verglichen. Ansonsten ist hier die gleiche Verarbeitung implementiert wie in der Originalroutine.

Dialogboxen im Programm

Um nun ein Programm mit diesen Dialogboxen auszustatten, ist folgendes Vorgehen zu empfehlen:

  1. Ermitteln der Koordinaten der Dialogbox. Dazu werden die Koordinaten aus der Objektstruktur ausgelesen.
  2. Berechnen der Fenstergröße aus der Größe der Dialogbox. Mit wind_calc wird das Border-Rechteck berechnet. Als Fensterelemente werden nur der Name und der Move-Balken benötigt.
  3. Mit wind_create wird ein entsprechendes Fenster mit den errechneten Maximal-Koordinaten angefordert.
  4. Ist dies nicht möglich, wird mit einer Fehlermeldung abgebrochen. Die Fehlermeldung kann mit Hilfe von form_alert ausgegeben werden.
  5. War der wind_create-Aufruf erfolgreich, können mittels form_dial ein Bildschirmbereich reserviert und ein wachsendes Rechteck gezeichnet werden. Die Dialogbox wird, wenn erforderlich, mit Initialwerten gefüllt.
  6. Das Fenster wird mit wind_open geöffnet und die Dialogbox wird mit objc_draw gezeichnet.
  7. Aufruf von Form_Do zur Verwaltung der Dialogbox
  8. Verarbeitung der Eingaben aus der Dialogbox
  9. Mit form_dial ein schrumpfendes Rechteck zeichnen und den reservierten Bildschirmbereich wieder freigeben. Schließen und Löschen des Fensters mit wind_close und wind_delete.
Bild 3: Das Menü

Obige Schritte stellen eine Vorgabe dar, die nicht unbedingt so eingehalten werden muß. Jeder Programmierer muß selbst wissen, welche der Schritte er wegläßt oder an eine andere Stelle setzt. Wichtig ist lediglich, daß das Fenster-Handle immer wieder freigegeben wird, da sonst über kurz oder lang keine Fenster mehr geöffnet werden können. Bei der Programmierung gibt es aber noch eine Menge mehr zu beachten. Läuft das Programm, kann, wenn eine Dialogbox aktiv ist, die Menüleiste bedient werden. Es ist also möglich, in die FormDo-Routine auch eine Verwaltung der Menüleiste zu implementieren. Dann muß aber beachtet werden, daß dieselbe Prozedur in einem Programm mehrmals gleichzeitig aufgerufen werden kann. Das führt in den meisten Fällen zu großen Problemen. Es gibt aber eine einfache Lösung. Beim Eintritt in die Prozedur wird der entsprechende Eintrag in der Menüleiste inaktiviert. Wird die Prozedur verlassen, wird dieser Eintrag wieder aktiv. Eine andere Möglichkeit stellt ein globales Flag dar, daß TRUE ist, wenn bereits eine Prozedur aus dem Menü-Handler heraus aufgerufen wurde und diese noch aktiv ist. Das Flag wird im Menü-Handler beim Verlassen der Prozedur auf FALSE gesetzt. Es ist dann nicht mehr möglich, aus demselben Programm eine weitere Aktion zu starten, bis die momentan laufende beendet wird.

Als weitere Erweiterung wäre z.B. eine Online-Hilfe denkbar. Die Help-Taste kann in der FormDo-Routine abgefragt werden. Die Online-Hilfe kann dann auch aus Dialogboxen heraus angesprungen werden. Zusätzlich müßte eine globale Variable eine Kennung für den auszugebenden Text enthalten.

Beispielprogramm

Listing 3 enthält einen Auszug aus dem Beispielprogramm. Es werden im Programm zwei Dialogboxen verwaltet - zum einen die Copyright-Meldung, zum anderen eine Eingabemaske, wie sie in einer Adreßverwaltung denkbar wäre. Die Verwaltung der Eingabemaske sehen Sie in Listing 3. Die Daten werden im Programm nicht ausgelesen und verarbeitet. Vor dem Öffnen der Dialogbox werden die Felder mit einem Null-String initialisiert. Die Prozedur DoAdresse übernimmt die Verwaltung der Adreßmaske.

Sie werden sich vielleicht fragen, warum keine Resource-Datei geladen wird. Sie wurde mit einem Programm, das nach einer Idee von Bruno Volkmer programmiert ist (siehe ST Computer 12/91), in einen Pascal-Quelltext übersetzt, der aus Platzgründen nur auf der Monatsdiskette zu diesem Heft enthalten ist. Die Adressen der einzelnen Objekte werden im Hauptprogramm ermittelt. Es kann die Resource-Datei aber jederzeit mit rsrc_load geladen werden.

Noch ein Wort zur Programmierung. Die Unit UtilAes (Listing 1) enthält alle Definitionen, wie ich sie für die Arbeit mit Objektbäumen benutze. Sie ist ebenfalls komplett auf der Monatsdiskette zu diesem Heft enthalten. Gegebenenfalls müssen die Definitionen an eigene angepaßt oder durch eigene ersetzt werden. Konstanten stammen, soweit sie nicht deklariert sind, aus den zu MAXON Pascal mitgelieferten Units GemDecl bzw. Gem-Aes. Die Bilder 1 und 2 zeigen das Aussehen der Dialogboxen. Bild 3 stellt die Menüleiste dar. Die Konstanten für die einzelnen Objekte sind im Listing 2 enthalten und können ohne Probleme zugeordnet werden. Alle Konstant in der Menüleiste beginnen mit dem Buchstaben „M“.

Für die Zukunft...

Multitasking ist eine feine Sache. Mit der entsprechenden Rechenleistung ausgestattet, läßt sich wirklich vernünftig arbeiten. Bei mir verrichtet seit kurzer Zeit Multi-GEM 2 seinen Dienst. Alle meine Programme, die Dialogboxen benutzen, legen diese jetzt in Fenster. So ist es z.B. möglich, daß TeX weiter übersetzt und Ausgaben am Bildschirm macht, während ein Programm auf eine Eingabe in eine Dialogbox wartet. Es ist wünschenswert, viele Programme mit diesen oder ähnlichen Dialogboxen auszustatten. Das Arbeiten geht dadurch flüssiger.

Literatur:

[1] ATARI Profibuch, Sybex Verlag, 12. Auflage 1992

[2] ST-Computer 12/91, Manipulationen des RSC-Files - Teil 1, Bruno Volkmer

[3] ST-Computer 02/92, Form_keybd & form_button, Wolfgang Sattler

[4] MultiGEM2-Handbuch


(* (c) 1992 MAXON Computer *)

(***********************************************) 
(* Funktion:         FORM BUTTON               *)
(* Zweck:            Eingaben in Dialogboxen   *)
(*                   verwalten                 *)
(* Eingabeparameter: fo_ktree      -> Zeiger a.*)
(*                                  Objektbaum *)
(*                   fo_kobject    -> zu bear- *)
(*                                    beitendes*)
(*                                    Objekt   *)
(*                   fo_kobnext    -> Nächstes *)
(*                                    Objekt   *)
(*                   fo_kchar      -> Zeichen  *)
(* Ausgabeparameter: fo_knextobject-> Nächstes *)
(*                                    Objekt   *)
(*                   fo_knextchar  -> Nächstes *)
(*                                    Zeichen  *)
(* Rückgabe:         0, wenn OK, <> 1 sonst    *)
(***********************************************)

    function form_button( fo_btree: TreePtr;
                          fo_bobject, 
                          fo_bclicks: Integer; 
                      var fo_bnxtobj: Integer)
                                    : Integer;

(***********************************************)
(* Funktion:         FORM_KEYBD                *)
(* Zweck:            Eingaben in Dialogboxen   *)
(*                   verwalten                 *)
(* Eingabeparameter: fo_ktree      -> Zeiger   *)
(*                                    auf Ob-  *)
(*                                    jektbaum *)
(*                   fo_kobject    -> Zu bear- *)
(*                                    beitendes*)
(*                                    Objekt   *)
(*                   fo_kobnext    -> Nächstes *)
(*                                    Objekt   *)
(*                   fo_kchar      -> Zeichen  *)
(* Ausgabeparameter: fo_knextobject-> Nächstes *)
(*                                    Objekt   *)
(*                   fo_knextchar  -> Nächstes *)
(*                                    Zeichen  *)
(* Rückgabe:         0, wenn OK, <> 1 sonst    *)
(***********************************************)

    function form_keybd ( fo_ktree : TreePtr;
                          fo_kobject, 
                          fo_kobnext, 
                          fo_kchar: Integer; 
                      var fo_knextobject,
                          fo_knextchar: Integer)
                                      : Integer;

(***********************************************)
(* Funktion:         DO_FORM                   *)
(* Zweck:            Dialogverwaltungsroutine  *)
(* Eingabeparameter: applid      -> Applika-   *)
(*                                  tationsId  *)
(*                   fenster     -> Fenster, in*)
(*                                  dem der    *)
(*                                  Dialog     *)
(*                                  läuft      *)
(*                   tree        -> Zeiger auf *)
(*                                  den Objekt-*)
(*                                  baum       *)
(*                   start_field -> erstes edi-*)
(*                                  tierbares  *)
(*                                  Feld       *)
(* Ausgabeparameter: keine                     *)
(* Rückgabe:         selektiertes Exit-Objekt  *)
(* Bemerkungen:      Ist kein Default-Objekt im*)
(*                   Dialog, so wird die       *)
(*                   Return-Taste automatisch  *)
(*                   wie die Tab-Taste benutzt,*)
(*                   d.h. der Cursor sprint ins*)
(*                   nächste editierbare Feld. *)
(*                   Wird zur Tab-Taste die    *)
(*                   Shift-Taste gedrückt,     *)
(*                   springt der Cursor ins    *)
(*                   vorhergehende editierbare *)
(*                   Feld.                     *)
(***********************************************)

Function FormDo( applid, fenster: Integer;
                var tree: TreePtr;
                start_field: Integer):Integer;

(***********************************************)
(*                                             *)
(* Und so ist's realisiert                     *)
(*                                             *)
(***********************************************)

implementation (* Internas der Unit *)

{$F+}

(* Unit-Interne Deklarationen *)

var aespb : ^AESParBlk; 
    version,
    GlobalEdit: Integer;

procedure AesCall;ASSEMBLER; 
ASM
    move.l  aespb,d1
    move.w  #200,d0 
    trap    #2
end;

function form_button( fo_btree: TreePtr;
                    fo_bobject,
                    fo_bclicks: Integer; 
                var fo_bnxtobj; Integer): Integer;
begin
    aespb^.adrin^[0]  := fo_btree;
    aespb^.intin^[0]  := fo_bobject;
    aespb^.intin^[1]  := fo_bclicks;
    aespb^.control^[0]:= 56; 
    aespb^.control^[1]:= 2; 
    aespb^.control^[2]:= 2; 
    aespb^.control^[3]:= 1; 
    aespb^.control^[4]:= 0;

    AesCall;

    fo_bnxtobj := aespb^.intout^[1]; 
    form_button:= aespb^.intout^[0]; 
end;

function form_keybd(    fo_ktree: TreePtr;
                        fo_kobject, 
                        fo_kobnext, 
                        fo_kchar: Integer; 
                    var fo_knextobject,
                        fo_knextchar : Integer)
                                     : Integer;

begin
    aespb^.adrin^[0]  := fo_ktree;
    aespb^.intin^[0]  := fo_kobject;
    aespb^.intin^[1]  := fo_kchar;
    aespb^.intin^[2]  := fo_kobnext;
    aespb^.control^[0]:= 56; 
    aespb^.control^[1]:= 3; 
    aespb^.control^[2]:= 3; 
    aespb^.control^[3]:= 1; 
    aespb^.control^[4]:= 0;

    AesCall;

    fo_knextobject  := aespb^.intout^[1]; 
    fo_knextchar    := aespb^.intout^[2]; 
    form_keybd      := aespb^.intout^[0]; 
end;

Procedure DoRedraw(tree: TreePtr;
                   fenster,
                   x,
                   y,
                   w,
                   h: Integer);
var r1, r2: Greet; 
begin
    (* Koordinaten des Bildschirmbereichs in die 
       Rechteckstruktur r1 eintragen *)

    r1.x := x; 
    r1.y := y; 
    r1.w := w; 
    r1.h := h;

    (* Bildschirm fur andere Applikationen für 
       die Dauer des Updates sperren und Maus 
       ausschalten *)

    wind_update(BEG_UPDATE); 
    graf_mouse(M_OFF, NIL);

    (* Erstes Rechteck aus der Rechteckliste holen *)

    wind_get(fenster, WF_FIRSTXYWH, r2.x, r2.y,
                                    r2.w, r2.h);

    while (* Solange nicht leer *)
        (r2.w <> 0) and (r2.h <> 0)
    do
    begin
        if (* Uberlappungsbereich ermitteln *) 
            Intersect(rl, r2) 
        then 
        begin
                (* Dialogbox im Uberlappungsbereich 
                   neu zeichnen. Dieser Bereich 
                   befindet sich in der Rechteckstruktur r2 *)

            objc_draw(tree, 0, 8, r2.x, r2.y, r2.w, r2.h);
        end;

        (* Nächstes Rechteck aus der Rechteckliste holen *)

        wind_get(fenster, WF_NEXTXYWH, r2.x, r2.y,
                                       r2.w, r2.h);
    end;

    (* Das war's; Maus an, Bildschirm wieder freigeben *)

    graf_mouse(M_ON, NIL); 
    wind_update(END_UPDATE); 
end;

Procedure DoMove(var tree: TreePtr;
                     fenster,
                     x,
                     y,
                     applid: Integer); 
var ox, oy, ow, oh, wx, wy, ww, wh: Integer; 
    ScreenMaxX, ScreenMaxY, dummy: Integer; 
    pipe: Array[0..7] of Integer; 
begin
    (* Lage des Fensters ermitteln *)

    wind_get(fenster, WF_CURRXYWH, wx, wy,
                                   ww, wh);

    (* Maximale Bildschirmbreite und Bildschirmhbhe ermitteln*)

    wind_get(0, WF_WORKXYWH, dummy, dummy,
                             ScreenMaxX,
                             ScreenMaxY);

    (* Fenster soll nicht über den Bildschirmrand hinaus ragen *)

    if
        ((x + ww) > ScreenMaxX) 
    then
        x := ScreenMaxX - ww;

    if
        ((y + wh) > ScreenMaxY) 
    then
        y := ScreenMaxY - wh;

    (* Neue Fensterkoordinaten setzen und daraus 
       den neuen Arbeitsbereich ermitteln *)

    wind_set(fenster, WF_CURRXYWH, x, y, ww, wh); 
    wind_get(fenster, WF_WORKXYWH, ox, oy, ow, oh);

    (* Eintragen der Koordinaten in die Objekt-Struktur *)

    tree^[0].o_x := ox + 1; 
    tree^[0].o_y := oy + 1; 
    tree^[0].o_w := ow; 
    tree^[0].o_h := oh;

    (* WM_REDRAW-Meldung generieren und abschicken *)

    pipe[0] := WM_REDRAW; 
    pipe[3] := fenster; 
    pipe[4] := x; 
    pipe[5] := y; 
    pipe[6] := ww; 
    pipe[7] := wh;

    appl_write(applid, SizeOf(pipe), pipe); 
end;

function find_object(tree: TreePtr;
                     start_object, 
                     which: Integer): Integer; 
var return, object, flag,
    theflag, increment: Integer; 
begin
    object   := 0;
    flag     := EDITABLE;
    increment:= 1;

    case
        which
    of
        FMD_BACKWARD: begin
                        increment:= -1; 
                        object   := start_object + increment;
                      end;
        FMD_FORWARD:  begin
                        object   := start_object + increment;
                      end;
        FMD_DEFLT:    begin
                        flag     := DEFAULT; 
                      end;
    end;

    return := start_object;

    while
        (object >= 0)
    do
    begin
        theflag := tree^[object].o_flags; 

        if
            theflag & flag > 0 
        then
            return := object;

        if
            theflag & LASTOB > 0 
        then
            object := -1 
        else
            object := object + increment;
    end;

    find_object := return; 
end;

function ini_field(tree: TreePtr;
                   start_field: Integer):Integer;
begin
    if
        start_field = 0 
    then
        start_field := find_object(tree, 0, FMD_FORWARD);

    ini_field := start_field; 
end;

function FormDo( applid, fenster: Integer; 
                var tree: TreePtr; 
                start_field: Integer): Integer; 
var edit_object, next_object, which, cont, 
    TopWindow, default, dummy, idx, mx, 
    my, mb, ks, kr, br: Integer; 
    msg: Array_16; 
begin
    next_object:= ini_field(tree, start_field); 
    edit_object:= 0;
    GlobalEdit := 0; 
    cont       := 1;
    default    := find_object (tree, 0, FMD_DEFLT);

    while
        cont <> 0
    do
    begin
        if
            ((next_object <> 0) and 
            (edit_object <> next_object)) 
        then 
        begin
            edit_object:= next_object;
            GlobalEdit := edit_object; 
            next_object:= 0;

            objc_edit(tree, edit_object, chr(0), 
                      idx, EDINIT, idx);
        end;

        which := evnt.multi(19,1,1,1,
                            0,0,0,0,0,0,0,0,0,0,
                            msg,LoWord(0),
                            HiWord(0), 
                            mx,my,mb,ks,kr,br);

        wind_get(fenster, WF_TOP, TopWindow, dummy, dummy, dummy);

        if
            (which & MU_MESAG > 0) 
        then 
        begin 
            case
                msg[0]
            of
                WM_UNTOP : if
                                msg[3] = fenster 
                           then
                                objc_edit(tree,
                                          edit_object, 
                                          chr(0),idx, 
                                          EDEND, idx);
                WM_ISTOP : if
                                mag[3] = fenster 
                           then
                                objc_edit(tree,
                                          edit_object, 
                                          chr(0),idx, 
                                          EDINIT, idx); 
                WM_TOPPED: wind_set(fenster,
                                        WF_TOP, 
                                        msg[3],
                                        0, 0, 0);
                WM_REDRAW: DoRedraw(tree, msg[3],
                                          msg[4], 
                                          msg[5], 
                                          msg[6], 
                                          msg[7]);
                WM_MOVED:  DoMove(tree, msg[3], 
                                        msg[4], 
                                        msg[5],
                                        Applid);
            end;

            objc_edit(tree, edit_object, chr(0), 
                            idx, EDINIT, idx);
        end;

        if
            (which & MU_KEYBD > 0) and 
            (TopWindow = fenster) (* Unser Fenster ist oben ? *)
        then
        begin
            if
                (kr = TAB) (* Tab-Taste gedrückt ? *) 
            then 
            begin 
                if
                    (ks & 1 > 0) or 
                    (ks & 2 > 0)
                            (* dazu Shift gedrückt ? *)
                then
                begin
                    kr := Cur_Up;
                        (* Umsetzen in Cur_up-Taste *)
                end;
            end;

            if
                (default = 0) and 
                ((kr = RETURN) or 
                (kr = ENTER))
                        (* Return gedrückt und kein*) 
            then        (* Default-Objekt *)
            begin
                kr := TAB; (* In Tab-Taste umsetzen*) 
            end;

            cont := form_keybd(tree, edit_object, 
                               next_object, kr, 
                               next_object, kr);

            if
                kr <> 0 
            then 
            begin
                objc_edit(tree, edit_object, Chr(kr), 
                          idx, EDCHAR, idx);
            end;

        end;

        if
            (which & MU_BUTTON > 0) and 
            (TopWindow = fenster) 
        then 
        begin
            next_object:= objc_find(tree, 0, 8, 
                                    mx, my);

            if
                (next_object = -1) 
            then 
            begin
                next_object := 0;
            end
            else
            begin
                cont := form_button(tree,
                                    next_object, 
                                    br, next_object);
            end;
        end;

        if
            (cont =0) or 
            ((next_object <> 0) and 
            (next_object <> edit_object)) 
        then 
        begin
            objc_edit(tree,edit_object,chr(0),idx,
                        EDEND, idx) ;
        end;
    end;

    FormDo:= next_object; 
end;

begin
    aespb := Addr(AES_pb); (* AES-Parameterblock ermitteln *)

end.

const ADRESSE   = 0;    (* TREE *)
      ANREDE    = 2;    (* OBJECT in TREE #0 *)
      NAME1     = 4;    (* OBJECT in TREE #0 *)
      NAME2     = 6;    (* OBJECT in TREE #0 *)
      VORNAME   = 8;    (* OBJECT in TREE #0 *)
      STRASSE   = 10;   (* OBJECT in TREE #0 *)
      POSTF     = 12;   (* OBJECT in TREE #0 *)
      PLZ       = 14;   (* OBJECT in TREE #0 *)
      ORT       = 16;   (* OBJECT in TREE #0 *)
      TELEFON   = 18;   (* OBJECT in TREE #0 *)
      FAX       = 20;   (* OBJECT in TREE #0 *)
      PARTNER   = 22;   (* OBJECT in TREE #0 *)
      AKTION    = 23;   (* OBJECT in TREE #0 *)
      ABBRUCH   = 24;   (* OBJECT in TREE #0 *)
      MENU      = 1;    (* TREE *)
      MADRESSE  = 17;   (* OBJECT in TREE #1 *)
      MENDE     = 16;   (* OBJECT in TREE #1 *)
      MABOUT    = 7;    (* OBJECT in TREE #1 *)
      ABOUT     = 2;    (* TREE *)


(***********************************************)
(* (c) 1992 MAXON Computer                     *)
(* Prozedur DoAdresse - Darstellen der Adressen*)
(*                      Maske mit der neuen    *)
(*                      FormDo-Routine.        *)
(***********************************************)

    Procedure DoAdresse; 
    var auswahl, 
        fenster, 
        state,
        ox, wx,
        oy, wy, 
        ow, ww,
        oh, wh: Integer; 
        fenstertitel, 
        nachricht, 
        maske, 
        pr: String; 
    begin
        (* Ermitteln der Koordinaten der Dialogbox 
           aus der ObjektStruktur *)

        ox:= BaumAdresse^[0].o_x; 
        oy:= BaumAdresse^[0].o_y; 
        ow:= BaumAdresse^[0].o.w; 
        oh:= BaumAdresse^[0].o_h;

        (* Berechnen des Begrenzungerechtecks des Fensters *)

        wind_calc(WC_B0RDER, NAME + MOVER,
                             ox, oy, ow, oh, 
                             wx, wy, ww, wh);

        (* Windowhandle besorgen *)

        fenster:= wind_create(NAME + MOVER,
                              wx, wy, ww, wh);

        if
            fenster >0 (* Alles klar, es ist ein Fenster frei *)
        then
        begin
            (* Das Fenster braucht einen Titel *)

            FensterTitel:= ' Adressen verwalten ' + #00 + #00;

            (* Bildschirmbereich reservieren und ein 
               wachsendes Rechteck zeichnen *)

            form_dial(0,0,0,0,0,ox,oy,ow,oh); 
            form_dial(1,0,0,0,0,ox,oy,ow,oh);

            (* Fenstertitel eintragen *)

            wind_set(fenster,WF_NAME,
                             HiPtr(FensterTitel[1]), 
                             LoPtr(FensterTitel[1]), 
                             0, 0);

            (* Vorbelegen der Edit-Felder *)

            maske:='_______________________________';
            pr   :='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

            Set_Dedit(BaumAdresse, NAME1  , maske, pr, '', 3, TE_LEFT); 
            Set_Dedit(BaumAdresse, NAME2  , maske, pr, '', 3, TE_LEFT);
            Set_Dedit(BaumAdresse, VORNAME, maske, pr, '', 3, TE_LEFT);
            Set_Dedit(BaumAdresse, STRASSE, maske, pr, '', 3, TE_LEFT);
            Set_Dedit(BaumAdresse, ORT    , maske, pr, '', 3, TE_LEFT); 
            Set_Dedit(BaumAdresse, PARTNER, maske, pr, '', 3, TE_LEFT);
            Set_Dedit(BaumAdresse, TELEFON, maske, pr, '', 3, TE_LEFT); 
            Set_Dedit(BaumAdresse, FAX    , maske, pr, '', 3, TE_LEFT);

            maske:= '__________';
            pr   := 'XXXXXXXXXX';

            Set_Dedit(BaumAdresse, ANREDE, maske, pr, '', 3, TE_LEFT);

            maske:= '_________________';
            pr   := 'XXXXXXXXXXXXXXXXX';

            Set_Dedit(BaumAdresse, POSTF, maske, pr, '', 3, TE_LEFT);

            maske:= '_________________';
            pr   := 'XXXXXXXXXXXXXXXXX';

            Set_Dedit(BaumAdresse, PLZ, maske, pr, '', 3, TE_LEFT);

            (* Fenster öffnen und zeichnen der Dialogbox *)

            wind_open(fenster, wx, wy, ww, wh); 
            objc_draw(BaumAdresse, 0, 8, ox, oy, ow, oh);

            (* Verwalten der Dialogbox mit der neuen FormDo-Routine *)

            auswahl := FormDo(ApplId, fenster, BaumAdresse, ANREDE);

            (* Selektiertes Objekt zurücksetzen *)

            state:=obj_getstate(BaumAdresse,auswahl) XOR SELECTED; 
            obj_setstate(BaumAdresse,auswahl,state);

            (* Schrumpfendes Rechteck zeichnen und 
               den reservierten Bildschirmbereich 
               wieder freigeben *)

            form_dial(2,0,0,0,0,ox,oy,ow,oh); 
            form_dial(3,0,0,0,0,ox,oy,ow,oh);

            (* Fenster schließen und Fensterhandle freigeben *)

            wind_close(fenster);
            wind_delete(fenster);
        end
        else (* Kein Fenster frei *) 
        begin
            nachricht:='[3][Kein Fenster!| ][ OK ]';

            auswahl:= form_alert(1, nachricht[i]); 
        end; 
    end;

Thomas Krieger
Aus: ST-Computer 05 / 1993, Seite 90

Links

Copyright-Bestimmungen: siehe Über diese Seite