GEM-Programmierung: Dialog

Grundstrukturen einer Dialogbox

Eine geladene Ressource ist ein Array vom Typ OBJECT. In diesem Array wird eine Baumstruktur simuliert.
struct object {
   int ob_next, ob_head, ob_tail;         /* Verzeigerung im Baum */
   int ob_type;    /* Bezeichnet den Elementtyp, z.B. Eingabefeld */
   int ob_flags, ob_state;                  /* Stati des Elements */
   void * ob_spec;        /* der Zeiger auf eine externe Struktur */
   int ob_x, ob_y, ob_width, ob_height; /* Dimension des Elements */
} OBJECT;

Der Zeiger ob_spec zeigt auf eine externe Struktur, die abhängig vom ob_type ist.

Bei einem Eingabefeld zeigt ob_spec auf ein TEDINFO

struct tedinfo {
   char * te_ptext;
   char *te_ptmplt;
   char *te_pvalid;
   /* Diverse Eigenschaften, wie Zeichensatz, Farbe, etc... */
   ...
} TEDINFO;

Laden der Ressourcen

Die Ressourcendatei wird zur Laufzeit geladen und die Zeiger auf die Grundobjekte ermittelt. Meist erfolgt zu diesem Zeitpunkt auch der Aufbau der Menüleiste.
OBJECT Dialogadresse;

   if ( ! rcs_load("MEINPRG.RSC") ) {
      /* Datei fehlt... */
   } else {
      rcsc_gaddr( 0, DIALOGBOX, &Dialogadresse);
   }

Starten der Dialogbox

Mit der Funktion rcsc_gaddr ermittelt man die Adresse der zu startenden Dialogbox. Die Funktion objc_draw braucht diese Adresse zum Zeichnen einer Dialogbox. Ein anschließendes form_do mit dieser Adresse startet die Abarbeitung der modalen Dialogbox.

Die gleichen Adressen werden für den Zugriff auf die Dialoginhalte verwendet. Hier eine Funktion zum Belegen eines Textfeldes in einer Dialogbox. Benötigt wird die Adresse der Dialogbox, die ID (ObjektIndex) des Textfeldes und der zukünftige Inhalt.

BelegeEingabeFeld (OBJECT *Dialogbox, int ObjektIndex, char *Inhalt)
{
TEDINFO *Eingabefeld;

   Eingabefeld = (TEDINFO *) Dialogbox[ObjektIndex].ob_spec;
   strcpy(Inhalt, Eingabefeld->te_ptext);
}
    . . .
    BelegeEingabeFeld(Dialogadresse, EINGABE, "Vorgabetext");
    . . .

Während die Funktion form_do aufgerufen wird, übernimmt das System die Kontrolle über das Programm. Die Funktion form_do endet dann, wenn der Benutzer ein Element angesprochen hat, das einen sogenannten Exitstatus besitzt. Mit diesem muß mindestens ein Element bei der Definition im Resouceneditor versehen worden sein, sonst endet die Dialogbox nie. Im Normalfall hat der OK- und der Abbruch-Knopf jeweils den Exitstatus. Der Index des angewählten Exitelemtes ist der Rückgabewert der Funktion form_do. Mit einer anschließenden Fallunterscheidung kann festgestellt werden, ob der Benutzer die Eingabe übernehmen oder verwerfen möchte.

Man kann auch anderen Elementen den Exitstatus geben, wenn man bei Zugriff auf das Element eine Aktion durchführen will. Man kann sogar einen Touch-Exit-Status vergeben, der form_do bereits unterbricht, wenn nur der Mauszeiger über dem Element steht. Da die Ausführung und die Darstellung unabhängig voneinander laufen, steht die Dialogbox immer noch auf dem Bildschirm, da sie noch nicht explizit entfernt wurde. Hier kann nun der Programmierer beliebige Aktionen ablaufen lassen und anschließend form_do erneut starten. Aus Benutzersicht ist diese Unterbrechung nicht wahrnehmbar.

Dieses Vorgehen wird zum Beispiel benutzt, wenn durch einen Knopfdruck Standardvorgabewerte in anderen Elementen gesetzt werden sollen. Der Standardknopf erhält den Exitstatus, wodurch form_do unterbrochen wird. Anhand des Rückgabewertes erkennt das Programm den Druckknopf für die Standardvorgabe und belegt die entsprechenden Elemente. Die betroffenen Teilbäume werden mit objc_draw neu gezeichnet und die Funktion form_do erneut aufgerufen. Dieser Vorgang ist hier im Beispiel skizziert:

   objc_draw (&DruckPara, . . .);
   do {
      exitbutton = form_do(DruckPara);
      switch (exitbutton) {
      case OK:  /* uebernehme Eingabe */
         /* hier erfolgt die normale Beendigung und das Auslesen
          * des Textfeldes */
         . . .
         break;
      case DINA4: /* Standardknopf */
         BelegeEingabeZeile(ZEILEN, DINA4TEXT);
         objc_draw(&InnenRahmen, . . . );
         break;
      case DINA5: /* Standardknopf */
         BelegeEingabeFeld(ZEILEN, DINA5TEXT);
         objc_draw(&InnenRahmen, . . .);
         break;
      case CANCEL: /* vergiss alle Eingaben */
         break;
      }
      . . .
   } while (exitbutton != OK) && (exitbutton != CANCEL);

Mit derselben Strategie sind auch geschachtelte Dialogboxen möglich, obwohl GEM diese eigentlich nicht unterstützt. Soll ein Element eine weitere Dialogbox auslösen, wird es im Ressourceneditor mit dem Exitstatus versehen. Stellt das Programm anhand des Rückgabewertes von form_do fest, daß dieses Element angewählt wurde, startet es die nächste Dialogbox. Nach Beendigung der inneren Dialogbox muß die äußere Dialogbox allerdings mit objc_draw neu gezeichnet werden, da es für Dialogboxen unter GEM keine REDRAW-Nachricht gibt.

Selbst neue Kontrollelemente können so erzeugt werden. GEM kennt von Haus aus kein Listenelement. Die Liste selbst kann durch Radio-Buttons ohne Rand simuliert werden, denen man die Einträge als Text unterschiebt. Schwieriger ist die Simulation des Rollbalkens. Dazu werden zwei verschiedenfarbige Rechteckelemente übereinandergelegt und mit dem Exitstatus versehen. Wird der innere Schieber angeklickt, führt das Anwenderprogramm das Verschieben des Schiebers aus, bis die Maustaste losgelassen wird. Dann verändert es die Position des Rahmenelements in der Objektstruktur, baut die Listenelemente neu auf und löst ein Neuzeichnen mit obj_draw aus. Anschließend wird form_do wieder aufgerufen.

Das Auslesen von Text aus einer Dialogbox

static char* EingabeString(OBJECT *baum, int Feld)
{
TEDINFO *ted;
char *inhalt;

	/* Errechne die Adresse der Eingabezeile */
	ted = (TEDINFO *)baum[Feld].ob_spec;
	inhalt = ted->te_ptext;
	return inhalt;
}

int KommaStellen(void)
{
int x, y, w, h, NKSt, exitobj;
OBJECT *komma_adr;
char *inhalt;

	NKSt =255; /* keine Formatierung */
	if (rsrc_gaddr (0, DIAKOMMA, &komma_adr)) {
		/* Errechne die Adresse der Eingabezeile */
		inhalt = EingabeString(komma_adr, STELLEN);
		strcpy(inhalt, "2");
		oeffneDialog(komma_adr);

		form_center (komma_adr,&x,&y,&w,&h); /* Koordinaten? */
		/* Ausfuehrung des Info Eintrags */
        exitobj = form_do (komma_adr,0);
        schliesseDialog(komma_adr);
        objc_change (komma_adr,exitobj,0,x,y,w,h,0,0);
        if (exitobj==NKOK) {
        	NKSt = atoi(inhalt);
        }
	}
	return NKSt;
}


Computer-Oldies - Atari ST Programmierung - Informatik-Ecke (C) Copyright 1999 Arnold Willemer