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.
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 |
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:
In diesem Eintrag wird hinterlegt, welches Fenster zum Neuanlegen und zum Ändern der Hauptinformation zu einem Objekt genommen werden soll.
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.
Hier erfolgt die Hinterlegung der Fenster, die die unterschiedlichen Detailinformationen zu den Objekten liefern können.
In diesem Element erfolgt die Hinterlegung des Fensters, in dem die Liste der Objekte dargestellt werden soll.
Hier wird die Regel hinterlegt, die die Liste in dem Übersichtsfenster auffüllen kann.
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();
}
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
{
}
}
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
{
}
}
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;
}
}
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
{
}
}
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";
}
}