4.3 Implementierung im Dialogskript

4.3.1 Namensgebung

Im Dialogskript wurde eine Namensgebung für die Objekte angewendet, so dass aufgrund des Namens die einzelnen Objekttypen erkannt werden können. Dieses Schema ist wie folgt aufgebaut:

[M]<Objektkennzeichen>ObjektName

M

Ist der erste Buchstabe ein "M", so handelt es sich um ein Modell bzw. eine Vorlage. Danach folgen die Buchstaben, die den Objekttyp kennzeichnen.

Objektkennzeichen

Für das Objektkennzeichen wurden folgende Abkürzungen verwendet:

Pb

bezeichnet Pushbutton

Wn

bezeichnet Fenster

Rc

bezeichnet Records

Et

bezeichnet Eingabefelder

Lb

bezeichnet Listboxen

Im

bezeichnet Bilder

ObjektName

Beschreibender Name des Objekts

4.3.2 Datenstrukturen

Die Klassenstruktur wird in einer Dialogstruktur abgebildet. Dazu werden mehrere Unterstrukturen gebildet, um später möglichst einfach alle Elemente verwalten zu können. Diese Struktur besteht aus folgenden Einzelstrukturen: Struktur für Aufträge, Struktur für Kunden, Struktur zum Abspeichern der Objekte, Struktur für die Methoden.

4.3.2.1 Auftragsstruktur

In der Auftragsstruktur werden alle zu einem Auftrag gehörenden Informationen abgelegt. Dazu gehören die Auftragsnummer, die Artikelnummer, die Anzahl, die Start-, Ende- und Liefertermine. Diese Struktur wird als Vorlage abgelegt, da beliebig viele Aufträge in das System eingegeben werden können.

!!Datenstruktur für den Auftrag

model record MRcAuftrag

{

  string AuftragsNr := "";

  string Artikel := "";

  integer Anzahl := 0;

  string FStart := "";

  string FEnde := "";

  string Liefer := "";

}

4.3.2.2 Kundenstruktur

Die Kundenstruktur umfasst alle Informationen, die den Kunden betreffen. Dazu gehören die Kundennummer, Firma, Anschrift und der Ansprechpartner.

!!Datenstruktur für den Kunden

model record MRcKunde

{

  string KundenNr := "";

  string Firma := "";

  string Strasse := "";

  integer Plz := 0;

  string Ort := "";

  string Partner := "";

  string Telefon := "";

  string Fax := "";

}

4.3.2.3 Struktur zum Abspeichern der Elemente

Damit beliebig viele Objekte (Kunden oder Aufträge) intern auch verwaltet werden können, gibt es eine Struktur, die zur Laufzeit in ihrer Größe an die Bedürfnisse angepasst werden kann. Dabei können in dem so realisierten Feld beliebig viele Objekte beliebiger Art abgespeichert werden

!!Datenstruktur zum Abspeichern der Werte. Die Struktur

!! wird bei Bedarf vergrößert.

model record MRcSpeicher

{

  object Elemente[5];

  .Elemente[1] := null;

  .Elemente[2] := null;

  .Elemente[3] := null;

  .Elemente[4] := null;

  .Elemente[5] := null;

}

Um nun in dieser Struktur Werte abzulegen, wurde die nachfolgende Regel definiert, die beliebige Elemente in diese Struktur übernehmen kann.

!!Aufnehmen eines neuen Elements in die Speicherliste

rule object Rl_NeuesElement (object ObjektInfo input)

{

  variable integer I;

  variable integer FreierPlatz := 0;

 

  !! Suchen nach einem freien Platz in der Liste

  for I:= 1 to ObjektInfo.MRcSpeicher.count[.Elemente] do

    if ((ObjektInfo.MRcSpeicher.Elemente[I] = null)

    and (FreierPlatz = 0)) then

      FreierPlatz := I;

    endif

  endfor

  !! Kein Platz gefunden: Speicherbereich muss

  !! vergrößert werden

  if (FreierPlatz = 0) then

    ObjektInfo.MRcSpeicher.count[.Elemente] :=

    (ObjektInfo.MRcSpeicher.count[.Elemente] + 10);

  !! Initialisierung der neuen Elemente mit null

  for I:=(ObjektInfo.MRcSpeicher.count[.Elemente] - 9) to

  ObjektIno.MRcSpeicher.count[.Elemente] do

    ObjektInfo.MRcSpeicher.Elemente[I] := null;

  endfor

  FreierPlatz:=(ObjektInfo.MRcSpeicher.count[.Elemente] -

    9);

  endif

 

  !! Generieren des neu zu speichernden Objekts

  ObjektInfo.MRcSpeicher.Elemente[FreierPlatz] :=

    create(ObjektInfo.ObjektArt, this.dialog);

  !! Rückgabe des neugenerierten Objekts

  return ObjektInfo.MRcSpeicher.Elemente[FreierPlatz];

}

4.3.2.4 Struktur zur Hinterlegung der Methoden

Dieses Objekt stellt das Kernstück des Beispiels dar. In der Methodenstruktur werden alle Methoden hinterlegt, die auf die unterschiedlichen Objekte im System angewendet werden können. Dazu wird zunächst bei allen Objekten untersucht, welche Methoden für sie realisiert werden müssen. In diesem Beispiel sind das folgende Methoden:

Create

In diesem Eintrag wird hinterlegt, welches Fenster zum Neuanlegen und zum Ändern der Hauptinformation zu einem Objekt genommen werden soll.

Init

Hier erfolgt die Hinterlegung der Initialisierungsfunktion, d.h. der Funktion, die eigentlich die notwendigen Daten aus der Datenbank laden soll. Da in diesem Beispiel keine Funktionen implementiert sind, ist hier jeweils nur eine Dummy-Regel hinterlegt.

Detail1-3

Hier erfolgt die Hinterlegung der Fenster, die die unterschiedlichen Detailinformationen zu den Objekten liefern können.

List

In diesem Element erfolgt die Hinterlegung des Fensters, in dem die Liste der Objekte dargestellt werden soll.

Rlist

Hier wird die Regel hinterlegt, die die Liste in dem Übersichtsfenster auffüllen kann.

Tlist

Dieser Eintrag enthält den Text, der als Überschrift für das Listenfenster dienen soll.

!!Dieses Objekt beschreibt die Methoden, die zu einem

!!Objekt vorhanden sind.

!!Create: Fenster zum Anlegen eines Objektes

!! (Grunddatenerfassung)

!!Init: Regel/Funktion zum Initialisieren der Datenstruktur

!!Detail[1]: Fenster für 1 Unterinformationen

!!Detail[2]: Fenster für 2 Unterinformationen

!!Detail[3]: ungenutzt

!!List: Fenster, in dem die Liste der Objekte angezeigt

!!werden soll

!!RList: Regel, die die Aufbereitung der Daten für die

!!Liste übernimmt

!!TList: Text, der als Titel im  Listenfenster erscheinen

!!soll

model record MRcMethoden

{

  object Create := null;

  object Init := null;

  object Detail[3];

  .Detail[1] := null;

  .Detail[2] := null;

  .Detail[3] := null;

  object List := null;

  object RList := null;

  string TList;

}

4.3.2.5 Objektstruktur

Die eigentliche Objektstruktur wird aus den anderen Strukturen zusammengesetzt. Dazu erhält diese Objektstruktur ein Element, in dem die Objektart (MRcAuftrag oder MRKunde abgespeichert wird. Daneben beinhaltet diese Struktur die beiden Unterstrukturen MRcSpeicher zum Abspeichern der Objekte und MRcMethoden zur Definition der Methoden, die zu dem Objekt gehören.

!!Struktur, die das Basisobjekt einer Objektklasse darstellt

model record MRObjekt

{

  object ObjektArt := null;

  child MRcSpeicher

  {

  }

  child MRcMethoden

  {

  }

}

4.3.2.6 Auftragsobjekt

Das Auftragsobjekt ist eine Instanz der Objektstruktur. Hier werden die entsprechenden Einträge für die Methoden entsprechend gesetzt.

!!Realisiertes Objekt für die Aufträge

MRObjekt RcAuftraege

{

  .ObjektArt := MRcAuftrag;

  .MRcMethoden.Create := MWnAuftrag;

  .MRcMethoden.Init := InitObjekt;

  .MRcMethoden.Detail[1] := MWnFertigung;

  .MRcMethoden.Detail[2] := Meldung;

  .MRcMethoden.List := MWnListe;

  .MRcMethoden.RList := RListAuftrag;

  .MRcMethoden.TList := "Auftragsliste";

}

4.3.2.7 Kundenobjekt

Das Kundenobjekt ist eine Instanz der Objektstruktur. Hier werden die entsprechenden Einträge für die Methoden entsprechend gesetzt.

!!Realisiertes Objekt für die Kunden

MRObjekt RcKunden

{

  .ObjektArt := MRKunde;

  .MRcMethoden.Create := MWnKunden;

  .MRcMethoden.Init := InitObjekt;

  .MRcMethoden.Detail[1] := MWnRechnung;

  .MRcMethoden.Detail[2] := Meldung;

  .MRcMethoden.List := MWnListe;

  .MRcMethoden.RList := RListKunde;

  .MRcMethoden.TList := "Kundenliste";

}

4.3.2.8 Übergeordnete Struktur

Um beim Programmstart und Programmende automatisch alle Datenstrukturen behandeln zu können, wurde eine übergeordnete Struktur gebildet, die nur Verweise auf die untergeordneten Strukturen beinhaltet. Dadurch kann z.B. beim Programmstart eine Schleife über alle intern vorhandenen Datenstrukturen gebildet werden, um diese entsprechend ihrer Initialisierungsmethode initialisieren zu lassen.

!!Die nachfolgende Datenstruktur dient nur dazu, alle

!!Strukturen beim

!!Programmstart zu initialisieren. Diese müssten natürlich

!!aus der Datenbank gelesen werden, was aber in diesem

!!Beispiel nicht implementiert worden ist. Damit Daten aber

!!erhalten bleiben, speichert der Dialog sich selbst wieder

!!ab. Dadurch bleiben auch die geänderten Werte erhalten.

record RcObjekttypen

{

  object Objekte[2];

  .Objekte[1] := RcAuftraege;

  .Objekte[2] := RcKunden;

}

4.3.3 Erweiterung der bestehenden Objekte

Die im DM vorhandenen Objekte wurden zum Teil durch eigene Attribute erweitert, so dass dort alle notwendigen Informationen abgespeichert werden können.

4.3.3.1 Erweiterungen beim Objekt window

Bei diesem Objekt wurden vier Attribute ergänzt, damit die Fenster alle mit denselben Regeln bearbeitet werden können. Über das Attribut "Dynamisch" wird gekennzeichnet, ob das Fenster im Fenster nur genau einmal offen sein darf oder ob das Fenster beliebig oft vom Anwender mit anderen Daten geöffnet werden darf. Die Attribute "MethodenObjekt" und "DargestelltesObjekt" sind Verweise, die zur Identifikation des im Fenster dargestellten Inhalts dienen. Das "MethodenObjekt" ist dabei ein Verweis auf das Grundobjekt der Aufträge oder Kunden, das "Dargestelltes Objekt" ist ein Verweis auf die interne Datenstruktur, die zu diesem Fenster gehört. In dem Attribut "ZuAktivierendesObjekt" wird gemerkt, welches Objekt beim Öffnen des Fensters aktiviert werden soll.

!!Attribute MethodenObjekt, DargestelltesObjekt, Dynamisch

!!und ZuAktivierendesObjekt eingefügt

!!Bedeutung der Attribute

!!MethodenObjekt enthält alles, was zu der Objektart gehört

!!DargestelltesObjekt ist das aktuelle Objekt, das in dem

!!Fenster gerade bearbeitet wird

!!Dynamisch ist ein Kennzeichen dafür, wie das Fenster beim

!!Unsichtbarmachen behandelt werden soll.

!!ZuAktivierendesObjekt enthält das Objekt, das beim

!!Fensteröffnen in dem Fenster aktiviert werden soll.

default window

{

  ...

  object MethodenObjekt := null;

  object DargestelltesObjekt := null;

  boolean Dynamisch := true;

  object ZuAktivierendesObjekt := null;

}

Neben diesen Attributerweiterungen wurde eine globale Regel für das Defaultfenster definiert, die das Sichtbar- und Unsichtbarmachen des Fensters handhaben kann. Beim Unsichtbarmachen muss geprüft werden, ob das Fenster dynamisch generiert wurde. Ist dies der Fall muss das Fenster intern wieder zerstört werden. Beim Sichtbarmachen eines neuen Fensters wird über diese Regel das richtige Objekt im Fenster aktiviert, so dass der Anwender sofort mit der Bearbeitung des Fensters beginnen kann.

!!Allgemeine Regel zum Behandeln sichtbar / unsichtbar

!!gemachter Fenster

on Dialog.WINDOW close, .visible changed

{

  variable integer I;

 

  if ( not this.visible) then

    !! Fenster ist dynamisch generiert worden, d.h. es muss

    !! jetzt wieder gelöscht werden

    if this.Dynamisch then

      !! Zerstören des Fensters

      destroy(this, true);

    endif

  else

    !! Fenster ist sichtbar gemacht worden.

    !! Suchen nach dem Objekt, das aktiviert bzw.

    !! fokussiert werden soll

    for I := 1 to this.childcount do

      if (this.window.child[I].model =

      this.window.model.ZuAktivierendesObjekt) then

        if (this.window.child[I].class = edittext) then

          this.window.child[I].active := true;

        else

          this.window.child[I].focus := true;

        endif

        return ;

      endif

    endfor

  endif

}

Wenn ein Fenster zu einem bestimmten Datensatz geöffnet werden soll, wird zunächst gesucht, ob dieses Fenster nicht schon offen ist. Dazu wird über alle Fenster gegangen und geprüft, ob das aktuell betrachtete Fenster zu dem gesuchten Objektgrundtyp gehört, die gesuchte Art hat und das gesuchte Datenobjekt darstellt. Wird so ein Fenster gefunden, wird von der Regel dieses gefundene Fenster zurückgegeben, ansonsten wird null zurückgegeben.

!!Diese Regel sucht in allen geöffneten Fenstern nach einem

!!Fenster mit vorgegebenen Daten. Wird dieses Fenster

!!gefunden, wird es als Ergebnis nach außen zurück

!!geliefert, sonst wird null geliefert

rule object Rl_SucheNachFenster (object ObjektInfo input, object FensterArt input, object DargObj input)

{

  variable integer I;

 

  !! Alle Kinder des Dialogs überprüfen

  for I := 1 to this.dialog.childcount do

    !! Schauen, ob das Objekt ein Fenster ist

    if (this.dialog.child[I].class = window) then

      !! Schauen, ob das Fenster zum gesuchten Methoden

      !! objekt gehört

      if(this.dialog.child[I].MethodenObjekt=ObjektInfo)

      then

        !! Schauen ob das Fenster zur gesuchten Fensterart

        !! gehört

        if (this.dialog.child[I].model = FensterArt) then

          !! Schauen, ob dieselbe Information dargestellt

          !! wird

          if (this.dialog.child[I].DargestelltesObjekt =

          DargObj) then

            return this.dialog.child[I];

          endif

        endif

      endif

    endif

  endfor

  !! Fenster nicht gefunden, null zurückliefern.

  return null;

}

Die nächste Regel legt ein Fenster einer definierten Art zu einem gegebenen Objekt an. Dabei wird das Fenster zunächst unsichtbar generiert, so dass die Daten noch im unsichtbaren Zustand in das Fenster gefüllt werden können

!!Anlegen eines Fensters für einen definierten Datensatz.

!!Zuerst wird überprüft, ob das Fenster nicht schon offen

!!ist und wieder verwendet werden kann. Ist das Fenster

!!als nicht dynamisch gekennzeichnet, so wird das

!! gefundene Fenster wiederverwendet

rule object FensterNeuAnlegen (object ObjektInfo input, object FensterArt input, object DargObj input)

{

  variable object Obj := null;

 

  !! überprüfen, ob eine Fensterart angegeben ist

  if (FensterArt <> null) then

    !! überprüfen ob die Fensterart ein Fenster oder eine

    !! Messagebox ist

    if (FensterArt.class = window) then

      !! überprüfen, ob das Fenster nicht schon existiert

      Obj := Rl_SucheNachFenster(ObjektInfo, FensterArt,

      DargObj);

      !! überprüfen, ob das Fenster dynamisch generiert

      !! werden soll

      if ((FensterArt.Dynamisch = true) and (Obj = null))

      then

        !! Unsichtbares Generieren des Fensters

        Obj := create(FensterArt, this.dialog, true);

      else

        !! Fenster aktivieren

        if (Obj <> null) then

          Obj.visible := true;

        else

          !! Daten neu in das statische Fenster setzen

          FensterArt.visible := true;

          Obj := FensterArt;

        endif

      endif

      !! Werte in das gefundene / neu generierte Fenster

      !! eintragen

      Obj.MethodenObjekt := ObjektInfo;

      Obj.DargestelltesObjekt := DargObj;

      return Obj;

    else

      !! Meldungsfenster öffnen

      querybox(FensterArt);

    endif

  endif

  return null;

}

4.3.3.2 Erweiterungen beim Objekt edittext

Beim Eingabefeld wurde ein Attribut ergänzt, das beschreibt, aus welchem Element der internen Struktur der Inhalt in dem Objekt angezeigt werden soll. Dazu wurde ein Attribut vom Typ "attribute" hinzugefügt, um das Attribut der Datenstruktur aufnehmen zu können.

default edittext

{

  ...

  attribute Datenelement := .visible;

}

Aufgrund dieser Erweiterung kann jetzt eine allgemeine Regel definiert werden, die die Daten vom Darstellungsobjekt zu den internen Strukturen bzw. umgekehrt kopiert. Dazu werden von einem gegebenen Fenster alle Kinder betrachtet und überprüft, ob sie ein Äquivalent in der internen Struktur haben. Wenn dies der Fall ist, werden die Werte ihren Datentypen entsprechend kopiert.

!!Regel zum Handhaben der Informationsanzeige und Übernahme

!!der geänderten Daten in die interne Struktur

rule void Rl_AnzeigeHandhaben (object ObjektInfo input, object Fenster input, boolean Display input)

{

  variable integer I;

 

  !! Daten sollen von der Anzeige in die interne Struktur

  !! übernommen werden

  if ( not Display) then

    !! Überprüfen, ob schon ein internes Objekt existiert

    if (Fenster.DargestelltesObjekt = null) then

      !! Anlegen eines internen Objekts

      Fenster.DargestelltesObjekt :=

      NeuesElement(ObjektInfo);

    endif

    if (Fenster.DargestelltesObjekt <> null) then

    !! Durchlaufen der Kinder des Fensters und Übernehmen

    !! der Werte in die interne Struktur

    for I := 1 to Fenster.childcount do

    !! Überprüfen, ob das Objekt ein Edittext ist

    if (Fenster.child[I].class = edittext) then

      !! Überprüfen, ob das Objekt zu einem sinnvollen

      !! Attribut gehört

      if (Fenster.child[I].Datenelement <> .visible) then

      !! Überprüfen des Datentyps der internen Struktur

      if (Fenster.DargestelltesObjekt.type

        [Fenster.child[I].Datenelement] = integer) then

        !! Überprüfen, ob wirklich eine Zahl eingetragen

        !! worden ist

        if fail(atoi(Fenster.child[I].content)) then

        !! Übernehmen des Werts in die interne Struktur

        setvalue(Fenster.DargestelltesObjekt,

          Fenster.child[I].Datenelement, 0);

        else

        !! Übernehmen des Werts in die interne Struktur

        setvalue(Fenster.DargestelltesObjekt,

          Fenster.child[I].Datenelement,

          atoi(Fenster.child[I].content));

        endif

      else

        !! Übernehmen des Werts in die interne Struktur

        setvalue(Fenster.DargestelltesObjekt,

          Fenster.child[I].Datenelement,

          Fenster.child[I].content);

      endif

      endif

    endif

    endfor

    !! Auswahlliste neu aufbauen

    ListeFuellen(Fenster.MethodenObjekt,

    InstanzVon(Fenster.MethodenObjekt.MRcMethoden.List,

      Fenster.MethodenObjekt));

  endif

  else

    !! Durchlaufen der Kinder des Fensters und Übernehmen

    !! der Werte in die interne Struktur

    for I := 1 to Fenster.childcount do

      !! Überprüfen, ob das Objekt ein Edittext ist

      if (Fenster.child[I].class = edittext) then

      !! Überprüfen, ob das Objekt zu einem sinnvollen

      !! Attribut gehört

      if (Fenster.child[I].Datenelement <> .visible) then

        if (Fenster.DargestelltesObjekt <> null) then

          if (Fenster.DargestelltesObjekt.type

            [Fenster.child[I].Datenelement] = integer)

          then

            !! Übernehmen des Werts in die Anzeige

            Fenster.child[I].content :=

              itoa(getvalue(Fenster.DargestelltesObjekt,

              Fenster.child[I].Datenelement));

          else

            !! Übernehmen des Werts in die Anzeige

            Fenster.child[I].content :=

              getvalue(Fenster.DargestelltesObjekt,

              Fenster.child[I].Datenelement);

          endif

        else

          !! Übernehmen des Werts in die Anzeige

          Fenster.child[I].content := "";

        endif

      endif

      endif

    endfor

  endif

}

Damit diese Regel richtig arbeiten kann, muss sie in der Lage sein, das für diesen Objekttyp zuständige Listenfenster zu bearbeiten. Dazu ist die nachfolgende Regel vorhanden.

!!Suchen nach einem Fenster, das die Instanz eines

!!vorgegebenen Modells ist

rule object InstanzVon (object Modell input, object Methode input)

{

  variable integer I;

 

  !! Alle Kinder des Dialogs betrachten

  for I := 1 to this.dialog.childcount do

    !! Überprüfen, ob das Objekt ein Fenster ist

    if (this.dialog.child[I].class = window) then

      !! Überprüfen, ob das Fenster Instanz des Modells

      !! ist

      if ((this.dialog.child[I].model = Modell)

      and (this.dialog.child[I].MethodenObjekt = Methode))

      then

        return this.dialog.child[I];

      endif

    endif

  endfor

  !! keine Instanz gefunden, Rückgabe von null.

  return null;

}

4.3.3.3 Erweiterungen beim Objekt image

Beim Bild wurde ein Attribut eingefügt, das einen Verweis auf das Methodenobjekt darstellt. Dadurch können bei Ereignissen auf Bildern die entsprechenden Methoden aufgerufen werden.

!!Attribut MethodenObjekt eingefügt.

!!Dieses Objekt enthält alle Informationen, die zu einem !!"Objekt" gemerkt werden müssen.

default image

{

   ..

  object MethodenObjekt := null;

}

4.3.3.4 Erweiterungen beim Objekt pushbutton

Der Pushbutton wurde um ein Attribut erweitert, das die aufzurufende Methode kennzeichnet.

!!Attribut AttributIndex eingefügt:

!!In diesem Attribut wird der Index der Methode gemerkt,

!!die bei Selektion des Pushbuttons aufgerufen werden soll.

default pushbutton

{

  ...

  integer AttributIndex := 0;

}

4.3.4 Definitionen für die einzelnen Fenster

4.3.4.1 Aktionen beim Programmstart und Programmende

Bei Programmstart werden die internen Datenstrukturen initialisiert. Im Normalfall sollten diese Werte aus der Datenbank gelesen werden. Darauf wurde in diesem Beispiel aber verzichtet. Damit aber die eingegebenen Werte nicht verloren gehen, wird beim Programmende der gesamte Dialog mit den eingetragenen Werten abgespeichert.

!!Diese Regel sorgt für die Initialisierung aller

!! Objektgrundtypen

rule void InitialisierenObjekte

{

  variable integer I;

 

  !! Durchlaufen aller RcObjekttypen

  for I := 1 to RcObjekttypen.count[.Objekte] do

    !! Überprüfen, ob wirklich ein Objekt gespeichert ist.

    if (RcObjekttypen.Objekte[I] <> null) then

      !! Aufruf der Initialisierungsmethode, falls diese

      !! vorhanden ist

      if (RcObjekttypen.Objekte[I].MRcMethoden.Init

      <> null) then

        RcObjekttypen.Objekte[I].MRcMethoden.Init(

          RcObjekttypen.Objekte[I].MRcSpeicher,

          RcObjekttypen.Objekte[I].ObjektArt);

      endif

    endif

  endfor

}

 

!!Abspeichern des aktuellen Dialogzustandes beim Beenden des Dialogs

on dialog finish

{

  save(this, "kunden.sav");

}

 

!!Startregel für das System

on dialog start

{

  InitialisierenObjekte();

}

 

!!Diese Regel sollte die Objekte eines Types initia-

!! lisieren, also sinnvollerweise aus der Datenbank laden

rule void InitObjekt (object Anker input, object Typus input)

{

  print "Hier m\201\341te das Laden aus der DB realisiert werden";

}

4.3.4.2 Das Startfenster

Das Startfenster besteht aus zwei Icons, die die unterschiedlichen Objektarten darstellen und aus einem Menü zum Auslösen der Aktion und zum Beenden des Dialogs.

!!Das nachfolgende Fenster erscheint beim Programmstart.

!!Von ihm aus können

!!die Fenster zu Kunden und Aufträge geöffnet werden.

window WnStart

{

  .userdata null;

  .active false;

  .xleft 400;

  .width 38;

  .ytop 396;

  .height 8;

  .title "Auswahl";

  .MethodenObjekt := null;

  .Dynamisch := false;

  child image IKunden

  {

    .xleft 5;

    .ytop 2;

    .text "Kunden";

    .picture TiKunde;

    .MethodenObjekt := RcKunden;

  }

  child image IAuftraege

  {

    .xleft 15;

    .ytop 2;

    .text "Auftr\344ge";

    .picture TiAuftrag;

    .MethodenObjekt := RcAuftraege;

  }

  child menubox MbAuswahl

  {

    .title "Auswahl";

    child menuitem MiListe

    {

      .text "Liste anzeigen";

    }

    child menuitem MiBeenden

    {

      .text "Beenden";

    }

  }

}

 

!!Menüeintrag zur Anzeige der Objektliste

on MiListe select

{

  variable object Obj;

  variable object NeuesObjekt;

 

  Obj := this.window.focus;

  !! Schauen, zu welchem Objekttyp die Fenster gezeigt

  !! werden sollen

  if (Obj.MethodenObjekt <> null) then

    NeuesObjekt := FensterNeuAnlegen(Obj.MethodenObjekt,

      Obj.MethodenObjekt.MRcMethoden.List, null);

    ListeFuellen(Obj.MethodenObjekt, NeuesObjekt);

    NeuesObjekt.visible := true;

  endif

}

 

!!Beenden des Systems

on MiBeenden select

{

  exit();

}

Abbildung 19-8: Startfenster

4.3.4.3 Das Übersichtsfenster

Im Übersichtsfenster werden die Listen aller Kunden oder Aufträge dargestellt. Über die Pushbuttons am unteren Ende des Fensters können die Aktionen ausgelöst werden. Dabei ist folgende Funktionsweise implementiert worden: Ein Doppelklick auf einen Eintrag in der Liste oder die Selektion des "Informations"-Pushbutton zeigt die Hauptdaten zum entsprechenden Datensatz an. Das sind dann entweder die Anschrift oder die Fertigungsdaten. Über den Pushbutton "Löschen" können Einträge in der Liste und damit auch in den internen Strukturen gelöscht werden. Durch Selektion des Pusbuttons "Neu" können neue Datensätze angelegt werden. Dieses Fenster ist als Vorlage hinterlegt, da es mehrmals zur gleichen Zeit mit unterschiedlichen Daten offen sein kann.

!!Modell für die Auflistung aller Objekte

model window MWnListe

{

  .userdata null;

  .active false;

  .xleft 78;

  .ytop 9;

  .title "Liste";

  .MethodenObjekt := null;

  .DargestelltesObjekt := null;

  .Dynamisch := true;

  .ZuAktivierendesObjekt := PNeu;

  child listbox LListe

  {

    .xauto 0;

    .xleft 3;

    .xright 3;

    .yauto 0;

    .ytop 0;

    .ybottom 1;

    .firstchar 1;

  }

  child pushbutton PNeu

  {

    .xleft 2;

    .yauto -1;

    .text "Neu";

  }

  child pushbutton PInfos

  {

    .sensitive false;

    .xleft 16;

    .yauto -1;

    .text "Informationen";

  }

  child pushbutton PLoeschen

  {

    .sensitive false;

    .xauto -1;

    .xright 13;

    .yauto -1;

    .text "L\366schen";

  }

  child MPOK

  {

  }

}

Abbildung 19-9: Auftragsliste

Zu diesem Fenster gehören die Regeln, die die Liste füllen können. Dazu wird über die jeweilige Objektstruktur gegangen und aus den vorhandenen Objekten die gewünschte Textinformation extrahiert und zur Anzeige gebracht. Dazu wird von den Objekten jeweils die Methode Rlist aufgerufen, die aus den internen Datenstrukturen die externe Repräsentation des Objektes generiert.

!!Aufbau des Anzeigestrings für die Auftragsliste

rule string RListAuftrag (object Auftrag input)

{

    return ((Auftrag.AuftragsNr + "    ") +

      Auftrag.Artikel);

}

 

!!Aufbau des Anzeigestrings für die Kundenliste

rule string RListKunde (object Kunde input)

{

    return ((((Kunde.KundenNr + "  ") + Kunde.Firma) +

      "   ") + Kunde.Ort);

}

 

!! Regel zum Füllen der Liste der Objekte

rule void ListeFuellen (object ObjektInfo input,

object Target input)

{

  variable string String;

  variable integer I;

!! Setzen des Fenstertitels

  Target.title := ObjektInfo.MRcMethoden.TList;

  !! Löschen aller vorhandenen Einträge

  Target.LListe.itemcount := 0;

  !! Insensitiv Schalten der Pushbuttons für Löschen und

  !! Detailinformationen

  Target.PLoeschen.sensitive := false;

  Target.PInfos.sensitive := false;

  !! Durchlaufen der Liste von Objekten und Einträgen in

  !! die Auswahlliste

  for I := 1 to ObjektInfo.MRcSpeicher.count[.Elemente] do

    !! Überprüfen, ob überhaupt ein Objekt gespeichert ist

    if (ObjektInfo.MRcSpeicher.Elemente[I] <> null) then

      !! String berechnen lassen

      String := ObjektInfo.MRcMethoden.RList

        (ObjektInfo.MRcSpeicher.Elemente[I]);

      !! String übernehmen

      if (String <> "") then

        Target.LListe.content[(Target.LListe.itemcount +

           1)] := String;

      endif

    endif

  endfor

}

Neben dieser Auflistungsfunktionalität gehören zu diesem Fenster noch Regeln, die die Selektierbarkeit der Pushbuttons steuern. Die Pushbuttons sollen nur selektierbar sein, wenn ein Eintrag in der Liste selektiert ist.

!!In Liste wird etwas selektiert, darum werden die

!!Pushbuttons "Löschen" und "Informationen" freigeschaltet

on LListe select

{

  this.window.PLoeschen.sensitive := true;

  this.window.PInfos.sensitive := true;

}

Zum Neuanlegen von Objekten wird das zugehörige Fenster ohne Inhalt auf den Bildschirm gebracht. Diese Aktion wird durch die Selektion des "Neu"-Pushbuttons ausgelöst.

!!Regel zum Neuanlegen eines beliebigen Objektes

rule void ObjektNeuAnlegen (object ObjektInfo input, object Info input)

{

  variable object Obj;

 

  !! Generieren des Fenster / Suchen nach vorhandenem

  !! Fenster

  Obj := FensterNeuAnlegen(ObjektInfo,

    ObjektInfo.MRcMethoden.Create, Info);

  !! Daten in Fenster setzen

  Rl_AnzeigeHandhaben(Obj.MethodenObjekt, Obj, true);

  !! Objekt sichtbar machen

  Obj.visible := true;

}

 

!!Regel zum Neuanlegen eines beliebigen Objekts

on PNeu select

{

  ObjektNeuAnlegen(this.window.MethodenObjekt, null);

}

Um bestehende Werte ändern zu können, wird auf die Selektion in der Listbox mit einem Doppelklick bzw. durch einfache Selektion des "Informationen"-Pushbutton durch Anzeige der entsprechenden Daten reagiert.

!!Information soll angezeigt werden.

on LListe dbselect

{

  InfosZeigen(this.window);

}

 

!!Information soll angezeigt werden.

on PInfos select

{

  InfosZeigen(this.window);

}

 

!!Regel zum Anzeigen der Information zu einem Objekt

rule void InfosZeigen (object Fenster input)

{

  variable object Obj;

 

  !! Überprüfen, ob ein Eintrag in der Liste selektiert

  !! ist.

  if (Fenster.LListe.activeitem <> 0) then

    !! Fenster anlegen und anzeigen

    Obj := FensterNeuAnlegen(Fenster.MethodenObjekt,

    Fenster.MethodenObjekt.MRcMethoden.Create,

      Fenster.MethodenObjekt.MRcSpeicher.Elemente

       [Fenster.LListe.activeitem]);

  Rl_AnzeigeHandhaben(Obj.MethodenObjekt, Obj, true);

  Obj.visible := true;

  endif

}

Beim Löschen über den "Löschen" Pushbutton werden auch die internen Strukturen entsprechend verändert.

!!Ein Objekt aus der Liste soll gelöscht werden

on PLoeschen select

{

  variable integer I;

 

  !! Durchsuchen aller Fenster, ob das zu löschende Objekt

  !! noch irgendwo angezeigt wird.

  for I := 1 to this.dialog.childcount do

    !! überprüfen, ob das Kind ein Fenster ist

    if this.dialog.child[I].class = window then

      !! Vergleichen des MethodenObjekts und des

      !! DargestelltenObjekts

      if this.dialog.child[I].MethodenObjekt =

        this.window.MethodenObjekt then

          if this.dialog.child[I].DargestelltesObjekt =

          this.window.MethodenObjekt.MRcSpeicher.Elemente

            [this.window.LListe.activeitem] then

            !! Ausblenden des Fensters

            this.dialog.child[I].visible := false;

          endif

      endif

    endif

  endfor

  if (this.window.LListe.activeitem > 0) then

  !! Zerstören der internen Struktur zu dem Fenster

  destroy(this.window.MethodenObjekt.MRcSpeicher.Elemente

    [this.window.LListe.activeitem], true);

  !! Schließen des zugehörigen Fensters

  this.window.MethodenObjekt.MRcSpeicher.Elemente

    [this.window.LListe.activeitem] := null;

  !! Neuaufbau der Liste

  ListeFuellen(this.window.MethodenObjekt, this.window);

  endif

}

4.3.4.4 Das Kundenfenster

Im Kundenfenster werden die direkt zu einem Kunden gehörenden Informationen wie Firmenname, Anschrift, Ansprechpartner und Telefon dargestellt. Dabei können die Daten in das Fenster neu eingegeben oder bestehende Daten verändert werden. Bevor dieses Fenster definiert wird, werden noch Vorlagen für die auch bei den Aufträgen auftretenden Pushbutton "Detailinformationen", "OK" und "Abbruch" definiert.

!!Modell für den Pushbutton, der Detailinformationen anfordert

model pushbutton MPDetail

{

  .yauto -1;

}

 

!!Modell für den OK Button

model pushbutton MPOK

{

  .xauto -1;

  .yauto -1;

  .text "OK";

}

 

!!Modell für den Abbrechen Pushbutton

model pushbutton MPAbbruch

{

  .xauto -1;

  .xright 13;

  .yauto -1;

  .text "Abbruch";

}

 

!!Meldungsfenster für noch nicht realisierte Teile im

!! Dialog.

messagebox Meldung

{

  .text "Noch nicht implementiert!";

  .title "Meldungsfenster";

  .button[2] nobutton;

}

 

!!Modell für das Kundeninformationsfenster

model window MWnKunden

{

  .userdata null;

  .active false;

  .xleft 467;

  .ytop 113;

  .height 13;

  .title "Kundeninformation";

  .MethodenObjekt := null;

  .DargestelltesObjekt := null;

  .Dynamisch := true;

  .ZuAktivierendesObjekt := EtKundenNr;

  child statictext

  {

    .xleft 2;

    .ytop 0;

    .text "Kunden-Nummer:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 1;

    .text "Firma:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 2;

    .text "Strasse:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 3;

    .text "PLZ:";

  }

  child statictext

  {

    .xleft 24;

    .width 0;

    .ytop 3;

    .height 0;

    .text "Ort:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 5;

    .text "Ansprechpartner:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 6;

    .text "Telefon:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 7;

    .text "Fax-Nummer:";

  }

  child MPDetail PAuftraege

  {

    .xleft 2;

    .yauto -1;

    .text "Auftr\344ge";

    .AttributIndex := 2;

  }

  child MPDetail

  {

    .xleft 20;

    .text "Rechnungen";

    .AttributIndex := 1;

  }

  child MPOK

  {

  }

  child edittext EtKundenNr

  {

    .xleft 15;

    .width 41;

    .ytop 0;

    .height 0;

    .Datenelement := .KundenNr;

  }

  child edittext EtFirma

  {

    .xleft 15;

    .width 41;

    .ytop 1;

    .height 0;

    .Datenelement := .Firma;

  }

  child edittext EtStrasse

  {

    .xleft 15;

    .width 41;

    .ytop 2;

    .height 0;

    .Datenelement := .Strasse;

  }

  child edittext EtPlz

  {

    .xleft 15;

    .width 7;

    .ytop 3;

    .height 0;

    .Datenelement := .Plz;

  }

  child edittext EtOrt

  {

    .xleft 28;

    .width 27;

    .ytop 3;

    .Datenelement := .Ort;

  }

  child edittext EPartner

  {

    .xleft 18;

    .width 38;

    .ytop 5;

    .Datenelement := .Partner;

  }

  child edittext EtTelefon

  {

    .xleft 18;

    .width 24;

    .ytop 6;

    .Datenelement := .Telefon;

  }

  child edittext EtFax

  {

    .active false;

    .xleft 18;

    .width 24;

    .ytop 7;

    .content "";

    .Datenelement := .Fax;

  }

  child MPAbbruch

  {

  }

}

Abbildung 19-10: Kundeninformation

Durch Selektion des Pushbutton "Rechnungen" werden die zu dem Kunden gehörenden Rechnungen in einem Fenster dargestellt. Die Querverbindung zu den Aufträgen ist in diesem Prototyp nicht realisiert, deshalb erscheint bei der Selektion des Pushbutton "Aufträge" eine entsprechende Meldung.

!!Regel zum Handhaben der Detailinformation 1

rule void Detail1Handhaben (object ObjektInfo input, object Fenster input, boolean Display input)

{

  variable integer I;

  variable object TFObj;

 

  !! Suchen nach dem Tablefield

  for I := 1 to Fenster.childcount do

  if (Fenster.child[I].class = tablefield) then

    TFObj := Fenster.child[I];

  endif

  endfor

  !! Jetzt sollte das Tablefield aus der Datenbank gefüllt

  !! werden.

  if (TFObj <> null) then

    if ( not Display) then

    endif

  endif

}

 

!!Anzeigen der Detailinformationen zu den Objekten

on MPDetail select

{

  variable object Obj;

  !! Fenster anlegen und anzeigen

  Obj := FensterNeuAnlegen(this.window.MethodenObjekt,

    this.window.MethodenObjekt.MRcMethoden.Detail

      [this.AttributIndex],

    this.window.DargestelltesObjekt);

  Detail1Handhaben(Obj.MethodenObjekt, Obj, true);

  Obj.visible := true;

}

Wenn der "OK"-Pushbutton selektiert wird, werden die im Fenster dargestellten Daten in die internen Strukturen übernommen.

!!Selektion des OK Buttons soll die Werte übernehmen

on MPOK select

{

  Rl_AnzeigeHandhaben(this.window.MethodenObjekt,

    this.window, false);

  this.window.visible := false;

}

Wenn der "Abbruch"-Pushbutton selektiert wird, werden die geänderten Daten verworfen und das Fenster geschlossen.

!!Die Selektion von Abbruch bewirkt das Unsichtbarmachen

!!des zugehörigen Fensters

on MPAbbruch select

{

  this.window.visible := false;

}

4.3.4.5 Das Auftragsfenster

Im Auftragsfenster werden die direkt zu einem Kunden gehörenden Informationen wie Firmenname, Anschrift, Ansprechpartner und Telefon dargestellt. Dabei können die Daten in das Fenster neu eingegeben oder bestehende Daten verändert werden. Dieses Fenster verfügt nicht über eigene Regeln, die notwendigen Regeln sind bereits alle im Zusammenhang mit dem Kundenfenster entstanden.

!!Modell für das Auftragsfenster

model window MWnAuftrag

{

  .userdata null;

  .active false;

  .xleft 305;

  .ytop 44;

  .title "Auftragsinformation";

  .MethodenObjekt := null;

  .DargestelltesObjekt := null;

  .Dynamisch := true;

  .ZuAktivierendesObjekt := EtAuftragsNr;

  child statictext

  {

    .xleft 2;

    .ytop 0;

    .text "Auftrags-Nummer:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 1;

    .text "Artikel:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 2;

    .text "Anzahl:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 3;

    .text "Fertigungs-Starttermin:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 4;

    .text "Fertigungs-Endetermin:";

  }

  child statictext

  {

    .xleft 2;

    .ytop 5;

    .text "Liefertermin:";

  }

  child edittext EtAuftragsNr

  {

    .xleft 16;

    .width 39;

    .ytop 0;

    .height 0;

    .Datenelement := .AuftragsNr;

  }

  child edittext EtArtikel

  {

    .xleft 16;

    .width 38;

    .ytop 1;

    .height 0;

    .Datenelement := .Artikel;

  }

  child edittext EtAnzahl

  {

    .xleft 16;

    .width 9;

    .ytop 2;

    .height 0;

    .Datenelement := .Anzahl;

  }

  child edittext EtFStart

  {

    .xleft 21;

    .width 17;

    .ytop 3;

    .Datenelement := .FStart;

  }

  child edittext EtFEnde

  {

    .xleft 21;

    .width 17;

    .ytop 4;

    .Datenelement := .FEnde;

  }

  child edittext EtLiefer

  {

    .xleft 21;

    .width 17;

    .ytop 5;

    .Datenelement := .Liefer;

  }

  child MPAbbruch

  {

  }

  child MPOK

  {

  }

  child MPDetail PMaschinen

  {

    .xleft 2;

    .yauto -1;

    .text "Maschinen";

    .AttributIndex := 2;

  }

  child MPDetail

  {

    .xleft 17;

    .text "Fert. Auftr\344ge";

    .AttributIndex := 1;

  }

}

Abbildung 19-11: Auftragsinformation

4.3.4.6 Das Rechnungsfenster

Im Rechnungsfenster sollen die zu einem Kunden gehörenden Rechnungen in einem Tablefield dargestellt werden. Dieses ist in diesem Prototyp nicht implementiert worden. Durch die Verwendung von Modellen verfügt dieses Fenster über keine eigenen Regeln.

!!Modell für das Rechnungsfenster

model window MWnRechnung

{

  .userdata null;

  .active false;

  .xleft 414;

  .ytop 156;

  .title "Rechnungen";

  .MethodenObjekt := null;

  .DargestelltesObjekt := null;

  .Dynamisch := true;

  .ZuAktivierendesObjekt := MPOK;

  child tablefield TfRechnungen

  {

    .xauto 0;

    .xleft 3;

    .xright 3;

    .yauto 0;

    .ytop 0;

    .ybottom 2;

    .fieldshadow false;

    .borderwidth 2;

    .colcount 4;

    .rowcount 5;

    .rowheadshadow false;

    .rowheader 1;

    .colheadshadow false;

    .colheader 0;

    .colfirst 1;

    .colwidth[2] 8;

    .colalignment[2] 0;

    .colalignment[3] 1;

    .colwidth[4] 5;

    .colalignment[4] 0;

    .content[1,1] "Rechnungs-Nr";

    .content[1,2] "Datum";

    .content[1,3] "Betrag";

    .content[1,4] "Status";

  }

  child MPOK

  {

  }

  child MPAbbruch

  {

  }

}

Abbildung 19-12: Rechnungsfenster

4.3.4.7 Das Fertigungsauftragsfenster

Im Fertigungsauftragsfenster sollen die zu einem Auftrag gehörenden Fertigungsaufträge in einem Tablefield dargestellt werden. Dieses ist in diesem Prototyp nicht implementiert worden. Durch die Verwendung von Modellen verfügt dieses Fenster über keine eigenen Regeln.

!!Modell für das Fenster für die Fertigungsaufträge

model window MWnFertigung

{

  .userdata null;

  .active false;

  .xleft 220;

  .ytop 55;

  .title "Fertigungsauftr\344ge";

  .MethodenObjekt := null;

  .DargestelltesObjekt := null;

  .Dynamisch := true;

  .ZuAktivierendesObjekt := MPOK;

  child MPAbbruch

  {

  }

  child MPOK

  {

  }

  child tablefield TfFertigung

  {

    .xauto 0;

    .xleft 3;

    .xright 3;

    .yauto 0;

    .ytop 0;

    .ybottom 2;

    .fieldshadow false;

    .borderwidth 2;

    .colcount 5;

    .rowcount 5;

    .rowheader 1;

    .colfirst 1;

    .colwidth[2] 10;

    .colwidth[3] 10;

    .colwidth[5] 15;

    .content[1,1] "Fertigungsauftrag";

    .content[1,2] "Starttermin";

    .content[1,3] "Endetermin";

    .content[1,4] "Maschine";

    .content[1,5] "Materialstatus";

  }

}

Abbildung 19-13: Fertigungsfenster