Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   dynamische Verwaltung von Objekten - Fahrstuhlsteuerung (https://www.delphipraxis.net/175307-dynamische-verwaltung-von-objekten-fahrstuhlsteuerung.html)

StuRic 11. Jun 2013 18:14

dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hallo liebe Community,

ich brauch eure Hilfe zu folgendem Problem: Ich will eine Fahrstuhlsteuerung programmieren, die eine beliebige Anzahl von Fahrstühlen, Etagen etc. verwalten & steuern kann. Die Lösung soll dabei objektorientiert gelöst werden. Daher war mein erster Gedanke bei der Steuerungsklasse eine Liste aller Fahrstühle einzufügen. Das sieht momentan so aus:
Code:
//_______Steuerung__________________
    pTFstKa = ^VFstKa;

    VFstKa = record
      FstKaX: ^Fahrstuhlkabine;   //Fahrstuhlkabine ist als Klasse deklariert
      next: PTFstKa;
    end;

    Steuerung = class
      id: cardinal;
      pFstKa: pTFstKa;
      procedure Fahrstuhl_Hinzu(id_in:cardinal; zulGewicht_in, EtageV_in, EtageB_in: integer; sNiAnEt: string);
      function Suche_Fahrstuhl(Suchkriterium, id_in, Stelle: cardinal):pTFstKa;
      constructor init(id_in: cardinal);
      destructor destruct();
    end;
Die Liste wird dabei folgendermaßen angelegt:

Code:
procedure Steuerung.Fahrstuhl_Hinzu(id_in:cardinal; zulGewicht_in, EtageV_in, EtageB_in: integer; sNiAnEt: string);
var FstKa: Fahrstuhlkabine;
    p,h: pTFstKa;
begin
  //Listenelement hinzufügen
  p:=pFstKa;
  new(h);
  h^.next:=nil;
  //Objektinitialisierung:
  FstKa:= Fahrstuhlkabine.Init(id_in, zulGewicht_in, EtageV_in, EtageB_in, sNiAnEt);
  h^.FstKaX:= @FstKa;
  //an Liste anfügen
  if pFstKa=nil then pFstKa:=h else
  begin
    while p^.next<>nil do begin
      p:=p^.next;
    end;
    p^.next:=h;
  end;
end;
Wenn ich nun mithilfe der Liste auf eine Instanz der Klasse "Fahrstuhlkabine" zugreife, bekomm ich leider eine Zugriffs-Exception.

Code:
  //________Laden der Aufzug-Eigenschaften des darzustellenden Aufzugs__________

  index:= Combob_FstKa.ItemIndex;

  p1:= Steuerung1.Suche_Fahrstuhl(2,0,index);
  Form.Caption:= 'Aufzug - Nr:' + inttostr(p1^.FstKaX^.id); //  <------ hier kommt dann die Exception
  ....
Mit google konnte ich mein Problem leider nicht bewältigen. Lediglich hab ich herausgefunden, dass es schon vorgefertigte Listen(-arten) gibt. Daher: Bitte helft mir! :wink:

Danke schonmal im Vorraus.

Grüße Ric


Edit: Falls mein Problem nicht deutlich geworden ist o.Ä. bitte nachfragen. Hauptsache ich bekomm ein Feedback. Danke!

Der schöne Günther 11. Jun 2013 21:35

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hallo und Willkommen in den heiligen Hallen des Wissens und des Wahnsinns :love:


Delphi-Quellcode kannst du in (Delphi)(/Delphi)-Tags (mit eckigen Klammern) packen. Das tue ich hier einmal, mit leichten Formatierungsänderungen:

Teil "Steuerung"
Delphi-Quellcode:
pTFstKa = ^VFstKa;
 
VFstKa = record
   FstKaX: ^Fahrstuhlkabine; //Fahrstuhlkabine ist als Klasse deklariert
   next: PTFstKa;
end;
 
Steuerung = class
   id: cardinal;
   pFstKa: pTFstKa;
   procedure Fahrstuhl_Hinzu(
      id_in:cardinal;
      zulGewicht_in, EtageV_in, EtageB_in: integer;
      sNiAnEt: string);
   function Suche_Fahrstuhl(Suchkriterium, id_in, Stelle: cardinal):pTFstKa;
   constructor init(id_in: cardinal);
   destructor destruct();
end;
"Liste anlegen"
Delphi-Quellcode:
procedure Steuerung.Fahrstuhl_Hinzu(
   id_in:cardinal;
   zulGewicht_in, EtageV_in, EtageB_in: integer;
   sNiAnEt: string
);
var
   FstKa: Fahrstuhlkabine;
   p,h: pTFstKa;
begin
   //Listenelement hinzufügen
   p:=pFstKa;
   new(h);
   h^.next:=nil;

   //Objektinitialisierung:
   FstKa:= Fahrstuhlkabine.Init(id_in, zulGewicht_in, EtageV_in, EtageB_in, sNiAnEt);
   h^.FstKaX:= @FstKa;

   //an Liste anfügen
   if pFstKa=nil then
      pFstKa:=h
   else begin
      while p^.next<>nil do begin
         p:=p^.next;
      end;
      p^.next:=h;
   end;
end;
"Laden der Aufzug-Eigenschaften des darzustellenden Aufzugs"
Delphi-Quellcode:
index := Combob_FstKa.ItemIndex;
 
p1 := Steuerung1.Suche_Fahrstuhl(2,0,index);
Form.Caption := 'Aufzug - Nr:' + inttostr(p1^.FstKaX^.id); // <------ hier kommt dann die Exception

Wieviel Theoriewissen über Objektorientierung und Anforderungserhebung habt ihr mit auf den Weg bekommen? Die Anforderung von dir sagt "Fahrstuhlsteuerung, die eine beliebige Anzahl von Fahrstühlen, Etagen etc. verwalten & steuern kann". Kannst du mehr dazu erzählen? Gerade zur Methode
Delphi-Quellcode:
Steuerung.Suche_Fahrstuhl(..)
und insbesondere den Parametern kann ich mir spontan gar nichts vorstellen :gruebel:


Zur Lösung des eigentlichen Problems: Entweder bin ich dumm (zum Ausgleich bin ich aber relativ schön), oder aus dem hier ersichtlichen Code lässt sich nichts finden. Meine Vermutung wäre, dass
Delphi-Quellcode:
Steuerung.Suche_Fahrstuhl(..)
keinen vernünftigen Zeiger zurückgibt, beispielsweise den Record nicht mittels
Delphi-Quellcode:
new()
auf dem Heap anlegt, sondern nur lokal "bei sich" auf dem Stack und dann einen Pointer auf Schrott zurückgibt.
Alternativ streicht bei mir der Debugger immer wieder gerne eine Zeile zu tief an, meint in Wirklichkeit die Zeile darüber. Setz doch mal einen Haltepunkt auf
Delphi-Quellcode:
p1 := Steuerung1.Suche_Fahrstuhl(2,0,index);
und geh dann schrittweise mit F7 durch und schau wo er rausfliegt.


Das bringt mich dann zu einem an sich erst einmal subjektiven Thema, hoffe aber, dass der Großteil der Belegschaft hier das ähnlich sieht: Ich finde den Code extrem schwer zu lesen, warum überhaupt die Records (und Zeiger)? Und warum keine gängigen Listentypen wie
Delphi-Quellcode:
TList
oder
Delphi-Quellcode:
TObjectList
? Ist das eine zwingende Vorgabe? Man muss doch nicht in jedem Projekt die verkettete Liste neu erfinden...

Zu Stilvorgaben und Namenskonventionen: Wie lange bist du schon bei Delphi dabei und von welcher Sprache kommst du? Mir kam es anfangs auch etwas dämlich vor, die Klassennamen immer mit T beginnen zu lassen, das ist sicher auch persönliches Gusto. Aber ich kann mir spontan keinen (hier passenden) Grund ausdenken, Konstruktoren und Destruktoren nicht
Delphi-Quellcode:
Create
und
Delphi-Quellcode:
Destroy
zu nennen, das bietet auf Dauer nur Verwirrungspotentiel.

Wenn ich jetzt noch damit anfange, dass zumindest mein Kopf es spontan nicht schafft, den Zweck hinter Variablennamen wie
Delphi-Quellcode:
sNiAnEt
oder
Delphi-Quellcode:
pFstKa
zu erkennen, wendest du dich wahrscheinlich wie jeder vernünftige Mensch angewidert vom Forum (insbesondere von mir) ab, da du eigentlich aus einem anderen Grund hergekommen bist. Aber ich denke dass es viel schwerer ist, überhaupt durcheinander zu kommen, wenn man nicht an Buchstaben spart und außen am Funktionskopf dokumentiert, wozu die Werte die rein- und rausgehen überhaupt gut sind.


Wie gesagt, spontan finde ich mit dem gegebenen Code keine Unstimmigkeit, ich tippe auf den oben genannten zwei Gründen auf einen Fehler in der nicht gegebenen Implementierung von
Delphi-Quellcode:
Steuerung1.Suche_Fahrstuhl

DeddyH 11. Jun 2013 21:44

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Hallo und Willkommen in den heiligen Hallen des Wissens und des Wahnsinns :love:

Schöner ist das IMHO noch nie gesagt worden, ich bin ganz gerührt *schnüff*

StuRic 12. Jun 2013 14:23

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Danke für die zügige Antwort.

Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)

Wieviel Theoriewissen über Objektorientierung und Anforderungserhebung habt ihr mit auf den Weg bekommen? Die Anforderung von dir sagt "Fahrstuhlsteuerung, die eine beliebige Anzahl von Fahrstühlen, Etagen etc. verwalten & steuern kann". Kannst du mehr dazu erzählen? Gerade zur Methode
Delphi-Quellcode:
Steuerung.Suche_Fahrstuhl(..)
und insbesondere den Parametern kann ich mir spontan gar nichts vorstellen :gruebel:

Die Problemstellung ergibt sich bei mir aus dem Fach Softwaretechnologie heraus. Dort ist in Prinzip nur ein Erstellen von Use-Case-Diagrammen, Systemsequenzdiagrammen und ein anschließendes Klassendesign gefordert. Allerdings dachte ich es ist einfacher/realitätsnaher wenn ich es implementiere und dann sehe was geht und was nicht :-D

Da ich das Ganze eher hobby-mäßig mache, beantwortet dass u.U. auch deine anderen Fragen:
Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Das bringt mich dann zu einem an sich erst einmal subjektiven Thema, hoffe aber, dass der Großteil der Belegschaft hier das ähnlich sieht: Ich finde den Code extrem schwer zu lesen, warum überhaupt die Records (und Zeiger)? Und warum keine gängigen Listentypen wie
Delphi-Quellcode:
TList
oder
Delphi-Quellcode:
TObjectList
? Ist das eine zwingende Vorgabe? Man muss doch nicht in jedem Projekt die verkettete Liste neu erfinden...

Ich hab mich bis dato noch nicht damit beschäftigt. In Zukunft werde ich bestimmt eine elegantere Lösung wählen...

Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Zu Stilvorgaben und Namenskonventionen: Wie lange bist du schon bei Delphi dabei und von welcher Sprache kommst du? Mir kam es anfangs auch etwas dämlich vor, die Klassennamen immer mit T beginnen zu lassen, das ist sicher auch persönliches Gusto. Aber ich kann mir spontan keinen (hier passenden) Grund ausdenken, Konstruktoren und Destruktoren nicht
Delphi-Quellcode:
Create
und
Delphi-Quellcode:
Destroy
zu nennen, das bietet auf Dauer nur Verwirrungspotentiel.

Guter Einwand! Werde ich überarbeiten.

Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Wenn ich jetzt noch damit anfange, dass zumindest mein Kopf es spontan nicht schafft, den Zweck hinter Variablennamen wie
Delphi-Quellcode:
sNiAnEt
oder
Delphi-Quellcode:
pFstKa
zu erkennen, wendest du dich wahrscheinlich wie jeder vernünftige Mensch angewidert vom Forum (insbesondere von mir) ab, da du eigentlich aus einem anderen Grund hergekommen bist. Aber ich denke dass es viel schwerer ist, überhaupt durcheinander zu kommen, wenn man nicht an Buchstaben spart und außen am Funktionskopf dokumentiert, wozu die Werte die rein- und rausgehen überhaupt gut sind.

Öhm,...Platzgründe (sNiAnEt = string für "nicht anzufahrende Etagen"...). Kritik ist angebracht und erwünscht. Also keine Sorge, was das betrifft :thumb:


So nun aber back to topic:
Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Gerade zur Methode
Delphi-Quellcode:
Steuerung.Suche_Fahrstuhl(..)
und insbesondere den Parametern kann ich mir spontan gar nichts vorstellen.

Delphi-Quellcode:
 Suche_Fahrstuhl
soll die Liste durchgehen und die zu suchende Instanz der Klasse Fahrstuhl in Form eines Zeigers darauf (pTFstKa) ausgeben. Es soll einerseits nach der ID und andererseits nach der Erstellungsreihenfolge gesucht werden. Letzteres brauchte ich um mit
Delphi-Quellcode:
Combob_FstKa.ItemIndex
arbeiten zu können...So sieht die Funktion zur Zeit aus:
Delphi-Quellcode:
function Steuerung.Suche_Fahrstuhl(Suchkriterium, id_in, Stelle: cardinal):pTFstKa;
var i: integer;
begin
  result:= pFstKa;
  case Suchkriterium of
    1: begin
      //Id.....
    end;
    2: begin
      i:= 1;
      while i < Stelle do
      begin
        result:= result^.next;
        i:= i + 1;
      end;
    end;
  end;
end;

Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Zur Lösung des eigentlichen Problems: Entweder bin ich dumm (zum Ausgleich bin ich aber relativ schön), oder aus dem hier ersichtlichen Code lässt sich nichts finden. Meine Vermutung wäre, dass
Delphi-Quellcode:
Steuerung.Suche_Fahrstuhl(..)
keinen vernünftigen Zeiger zurückgibt, beispielsweise den Record nicht mittels
Delphi-Quellcode:
new()
auf dem Heap anlegt, sondern nur lokal "bei sich" auf dem Stack und dann einen Pointer auf Schrott zurückgibt.

Klingt plausibel. Allerdings wird, wie oben erkennbar, kein neues Listenelement hinzugefügt...Evt habe ich dich aber auch falsch verstanden.

Zitat:

Zitat von Der schöne Günther (Beitrag 1218307)
Alternativ streicht bei mir der Debugger immer wieder gerne eine Zeile zu tief an, meint in Wirklichkeit die Zeile darüber. Setz doch mal einen Haltepunkt auf
Delphi-Quellcode:
p1 := Steuerung1.Suche_Fahrstuhl(2,0,index);
und geh dann schrittweise mit F7 durch und schau wo er rausfliegt.

Delphi-Quellcode:
Steuerung1.Suche_Fahrstuhl(..)
durchläuft er ohne Probleme. Exception gibt es es nach wie vor bei
Delphi-Quellcode:
Form.Caption:= 'Aufzug - Nr:' + inttostr(p1^.FstKaX^.id);
Mir fällt übrigens noch eine potentielle Stelle ein, die den Fehler evt. hervorrufen könnte: Die hier verwendete
Delphi-Quellcode:
Form
wird dynamisch als eine von vielen Instanzen von TForm2 erstellt und ebenfalls einer Liste hinzugefügt...

Delphi-Quellcode:
//Form-Listen
  pForm2 = ^VForm2;

  VForm2 = record
    Form: TForm2;
    next: pForm2;
  end;
...
var //global
  Form1: TForm1;
  Steuerung1: Steuerung;
  Fenster_FstKa: pForm2;

var //lokal
    p,h: pForm2;
    Form: TForm2;
...
//_____________________Form in die Formen-Liste aufnehmen_______________
  //Listenelement hinzufügen
  p:=Fenster_FstKa;
  new(h);
  h^.next:=nil;
  //Objektinitialisierung:
  Form:= TForm2.Create(Application);
  h^.Form:= @Form;
  //an Liste anfügen
  if Fenster_FstKa=nil then Fenster_FstKa:=h
  else begin
    while p^.next<>nil do
    begin
      p:=p^.next;
    end;
    p^.next:=h;
  end;
Ich werde noch ein wenig weitersuchen, damit ich meinen bisherigen Code nach Möglichkeit weiterverwenden kann. Ansonsten wäre es auch kein Problem die Aufgabenstellung mit
Delphi-Quellcode:
TObjectList
o. Ä. zu realisieren.
Daher bitte ich um eine beispielhafte Lösung für: Eine beliebige Anzahl Instanzen einer Klasse (z.B. Fahrstühle) soll in eine
Delphi-Quellcode:
TObjectList
bzw.
Delphi-Quellcode:
TComponentList
eingetragen werden und anschließend über die Liste angesprochen werden (Property verändern, Methode aufrufen o. Ä.)

Vielen Dank für eure Mühen!!! :wink:

StuRic 12. Jun 2013 15:09

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Moin,

Ich konnte mein Problem weiter eingrenzen:
Wenn ich eine Funktion zur Übergabe von Attributwerten wie folgt deklariere:
Delphi-Quellcode:
function Fahrstuhlkabine.test():integer;
begin
  result:=testvar;  //<----Exception hier!
end;
...
function Steuerung.Test():cardinal;
begin
  result:=pFstKa^.FstKaX^.test();
end;
...
//Aufruf Main-Unit:
  test:= Steuerung1.Test();
  showmessage(inttostr(test));
So ensteht nach wie vor die Zugriffs-Exception ganz egal ob ich
Delphi-Quellcode:
testvar
als private, public oder property deklariere. Wenn ich mir allerdings einen festen Wert zurückgeben lasse, ist alles super:
Delphi-Quellcode:
function Fahrstuhlkabine.test():integer;
begin
  result:=1001   //<----keine Exception!
end;
...
function Steuerung.Test():cardinal;
begin
  result:=pFstKa^.FstKaX^.test();
end;
...
//Aufruf Main-Unit:
  test:= Steuerung1.Test();
  showmessage(inttostr(test));
Die Vermutung liegt nahe, dass irgendwas mit der Attribut-Deklaration faul ist,....aber was?^^

Für das bessere Verständnis hier die Deklaration meiner Klasse
Delphi-Quellcode:
Fahrstuhlkabine
:
Delphi-Quellcode:
FahrstuhlKabine = class
      F_id: cardinal;
      fahrtrichtung: bool; // 1 = hoch // 0 = runter
      in_Benutzung: bool;
      Fahrtzeit: real;
      gewaehlteEtagen: pgewEt;
      speed: real;
      EtageV, EtageB, zulGewicht: integer;
      niAnEt: pNiAnEt;
    private
      F_position, F_tatsGewicht: real;
    public
      testvar:integer;
      property id: cardinal read F_id write F_id;
      property position:real read F_position write F_position;
      property tatsGewicht:real read F_tatsGewicht write F_tatsGewicht;
      constructor init(id_in:cardinal; zulGewicht_in, EtageV_in, EtageB_in: integer; sNiAnEt: string);
      destructor destruct();
      function zielAnfahren(Ziel:integer):bool;
      procedure set_Zieletage();
      procedure Notruf();
      function lastprobe():bool;
      function geschwindigkeitsmessung():bool;
      procedure notfallbremsen();
      function test():integer;
    end;
Hat jemand eine Idee woran es liegen könnte? :cyclops:

Der schöne Günther 12. Jun 2013 15:15

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hallo-

Ich kann es mir erst heute Abend genauer anschauen, aber bzgl:
Zitat:

Zitat von StuRic (Beitrag 1218380)
Die Vermutung liegt nahe, dass irgendwas mit der Attribut-Deklaration faul ist,....aber was?^^

Ich würde wagen zu behaupten, deine Fahrstuhlkabinen-Instanz ist Schrott. Bzw. der Zeiger darauf zeigt irgendwo hin, wo keine Fahrstuhlkabine ist. Die entsprechende Methode test() wird trotzdem aufgerufen, aber wenn dort drinnen man dann an die Variable testvar will, kommt man irgendwo hin, wo man nicht hinsoll - Zugriffsverletzung.

Halte im Debugger doch mal in der Funktion an - Kannst du in deiner Fahrstuhlkabinen-Instanz überhaupt irgendwelche brauchbaren Daten wiederfinden?

StuRic 12. Jun 2013 16:07

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hi,

jop, du hast Recht: Wenn ich innerhalb der
Delphi-Quellcode:
function Fahrstuhlkabine.test():integer;
begin
   result:=testvar; //Abtastpunkt hier
end;
einige Attribut-Werte über den Debugger anzeigen lassen will, steht "Nicht verfügbarer Wert" da...aber warum?

Wenn deine Vermutung mit dem Schrott-Zeiger richtig ist, fällt mir eine Stelle ein an der ein Fehler sein könnte:
Delphi-Quellcode:
...
//Objektinitialisierung:
  FstKa:= Fahrstuhlkabine.Init(id_in, zulGewicht_in, EtageV_in, EtageB_in, sNiAnEt);
  h^.FstKaX:= @FstKa;
...
Vielleicht ist die Adresszuweisung mithilfe von "@" bei Instanzen nicht funktionsfähig?

Bin schon sehr gespannt auf deine ausführliche Analyse :o

Sir Rufo 12. Jun 2013 16:34

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Kurze Grundlagen zu Klassen:

Klassen sind erstmal Typen und bekommen vor dem Namen ein
Delphi-Quellcode:
T
verpasst.

Der
Delphi-Quellcode:
constructor
heißt
Delphi-Quellcode:
Create
und sollte nach Möglichkeit auch so benutzt/benannt werden.
Delphi-Quellcode:
TMyObj = class
public
  constructor Create;
  constructor Init;
end;

constructor TMyObj.Create;
begin
  inherited;
  // irgendwas machen
end;

constructor TMyObj.Init;
begin
  inherited Create;
  // irgendwas machen
end;
Wird eine Klassen-Instanz erzeugt (mit dem
Delphi-Quellcode:
constructor
) so liefert mir selbiger eine Referenz auf die Klasse (als einen Zeiger).

Ein Zeiger auf eine Klassen-Referenz-Variable liefert mir also nur den Zeiger auf den Zeiger der Klasse. Lustig, gell?
(Das hört sich nicht nur komisch an, es ist auch komisch)

Für die Verwaltung von Klassen-Instanzen (man spricht dabei von Objekten), also eine Liste mit Objekten, gibt es die Hier im Forum suchenTObjectList.

Delphi-Quellcode:
var
  MyList : TObjectList;
begin
  // Liste erzeugen ...
  MyList := TObjectList.Create( True );
  try
    // ... mit ein paar Objekten füllen ...
    MyList.Add( TMyObj.Create );
    MyList.Add( TMyObj.Create );
    MyList.Add( TMyObj.Create );
  finally
    // und wieder freigeben
    MyList.Free;
  end;
end;
Das gibt auch kein Speicherleck, da
Delphi-Quellcode:
TObjectList.Create( True )
eine Liste erzeugt, die alle Objekte der Liste automatisch freigibt.

Somit solltest du deinen Ansatz mit dem ganzen Zeigergeraffel grundlegend über Bord werfen. ;)

Zu deiner Klasse selber
Delphi-Quellcode:
TFahrtRichtung = ( frRunter, frHoch );

//FahrstuhlKabine = class
TFahrstuhlKabine = class
  // diese Felder sind alle published ... eher unvorteilhaft
  // Der Zugriff sollte über Properties geregelt werden
      F_id: cardinal;
      //fahrtrichtung: bool; // 1 = hoch // 0 = runter
      Fahrtrichtung : TFahrtRichtung;
      In_Benutzung: bool;
      Fahrtzeit: real;
      gewaehlteEtagen: pgewEt;
      speed: real;
      EtageV, EtageB, zulGewicht: integer;
      niAnEt: pNiAnEt;
    private
      F_position, F_tatsGewicht: real;
    public
      testvar:integer;
      property id: cardinal read F_id write F_id;
      property position:real read F_position write F_position;
      property tatsGewicht:real read F_tatsGewicht write F_tatsGewicht;
      constructor init(id_in:cardinal; zulGewicht_in, EtageV_in, EtageB_in: integer; sNiAnEt: string);

      // !!! NEIN !!!
      // destructor destruct();

      destructor Destroy; override;

      function zielAnfahren(Ziel:integer):bool;
      procedure set_Zieletage();
      procedure Notruf();
      function lastprobe():bool;
      function geschwindigkeitsmessung():bool;
      procedure notfallbremsen();
      function test():integer;
    end;

StuRic 12. Jun 2013 18:16

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Moin,

Zitat:

Zitat von Sir Rufo (Beitrag 1218394)
Kurze Grundlagen zu Klassen:

Klassen sind erstmal Typen und bekommen vor dem Namen ein
Delphi-Quellcode:
T
verpasst.

Der
Delphi-Quellcode:
constructor
heißt
Delphi-Quellcode:
Create
und sollte nach Möglichkeit auch so benutzt/benannt werden.

Wird, wie gesagt, geändert und in Zukunft nicht mehr vorkommen...Ich wüsste allerdings gerne wozu man
Delphi-Quellcode:
inherited;
an dieser Stelle braucht...ist doch eher für vererbte Klassen nützlich oder täusch ich mich? Ich hab es bisher nie benutzt und auch nie vermisst...

Zitat:

Zitat von Sir Rufo (Beitrag 1218394)
Wird eine Klassen-Instanz erzeugt (mit dem
Delphi-Quellcode:
constructor
) so liefert mir selbiger eine Referenz auf die Klasse (als einen Zeiger).

Ein Zeiger auf eine Klassen-Referenz-Variable liefert mir also nur den Zeiger auf den Zeiger der Klasse. Lustig, gell?
(Das hört sich nicht nur komisch an, es ist auch komisch)

Vielen Dank! Genau das ist die Lösung für mein Problem :-D Sobald ich die "doppelte" Adressierung (mit @) gelöscht hatte, kam keine Exception mehr.


Delphi-Quellcode:
TFahrtRichtung = ( frRunter, frHoch );
...
Fahrtrichtung : TFahrtRichtung;
Mit dieser Änderung kann ich leider gar nichts anfangen...vermutlich dumme Frage, aber: wie setzt man da z.B. den Wert für "hoch"?

Sir Rufo 12. Jun 2013 18:43

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
z.B. so
Delphi-Quellcode:
Fahrtrichtung := frHoch;
Fahrtrichtung := frRunter;

case Fahrtrichtung of
  frRunter : ;
  frHoch : ;
end;

Union 12. Jun 2013 18:57

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Oder so:

Delphi-Quellcode:
TFahrtRichtung = (frHoch = 1, frRunter = -1);

Dann kann man die Richtung als Integer verwenden.

StuRic 13. Jun 2013 12:05

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Moin,

die dynamische Verwaltung meiner Objekte funktioniert soweit. An dieser Stelle ein dickes Dankeschön an alle Ratgeber :thumb:

Allerdings habe ich (leider) ein neues Problem: Wärenddessen eine Methode (hier:
Delphi-Quellcode:
function TTuer.schließen(...):bool
abgearbeitet wird, soll eine andere Methode diese unterbrechen können (hier:
Delphi-Quellcode:
 function TTuer.oeffnen(...):bool
.

Mein Versuch es über einen Attributwert zu machen, hat leider nicht funktioniert (...logisch: da die Methoden nacheinander abgearbeitet werden)...der Versuch sieht etwa so aus:
Delphi-Quellcode:
function TTuer.schließen(...):bool;
...
begin
  ...
  tuerSchließend:= true;
  while ... and (tuerSchließend) do
  begin
    //Tür Schließen
  end;
  tuerSchließend:= false;
end;

function TTuer.oeffnen(...):bool;
begin
  if tuerSchließend then tuerSchließend:= false;
  while ... do
  begin
    //Tür Öffnen
  end;
end;
Kann man mein Problem evt mit
Delphi-Quellcode:
Break
oder
Delphi-Quellcode:
GoTo
lösen? Wenn ja, bitte ein Beispiel mitgeben.
Wenn es ohne
Delphi-Quellcode:
Break
oder
Delphi-Quellcode:
GoTo
machbar ist, würd ich eine solche Lösung bevorzugen...

Grüße Ric

Der schöne Günther 13. Jun 2013 12:17

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Großer Gott, in diesen Fahrstuhl kriegen mich keine zehn Pferde :shock:

Ich gehe wieder an den Anfang zurück und unterstelle dir, nicht wirklich zu wissen, was du konkret eigentlich machen möchtest. Ein Computer arbeitet Dinge strikt nacheinander ab. Du kannst eine laufende Methode nicht von woanders unterbrechen:

Delphi-Quellcode:
meinFahrstuhl.öffneTüren();
warteMillisekunden(2000);
meinFahrstuhl.notAus();
Das öffnet erst die Türen und wartet anschließend nachdem das Öffnen abgeschlossen ist. Möchtest du Dinge asynchron (quasi "im Hintergrund") ausführen (das Öffnen), brauchst du Threads. Und davon würde ich fürs Erste abraten. Weder könntest du ohne eine laufende Methode "von außen" beeinflussen, noch in der Methode mitbekommen, was sich außen ändert - Da sich in der Zeit außen schlichtweg nichts ändert.

Hast du eine nahende Deadline? Ich würde mir erst einmal fest machen, was das Ding eigentlich konkret können soll, und WIE es das können soll. Beispielsweise einen hoch- und herunterfahrenden Aufzug zeichnen (ebenso wie öffnende und schließende Türen) - Auf Knopfdruck kann der Benutzer dann das Öffnen und Schließen veranlassen und bsp. einen laufenden Öffne/Schließevorgang abbrechen.


Zu Goto ist in den letzten Jahrzehnten eigentlich alles gesagt worden. Vergiss, dass es diesen Befehl gibt.

generic 13. Jun 2013 12:25

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Zurück kommend zu deinen ersten Beitrag. Du schreibst du möchtest das OOP lösen. Denn verwende doch bitte keinen Record und Zeigertypen. Der Record kann genau so ein Objekt (TObject etc.) sein.

Zu deinen Tür Beitrag.

Grundsätzlich hast du hier Statemaschines, welche Übergänge nach Ereignissen haben.

Im Fall der Tür:
1) Tür ist offen
2) Tür schließt
3) Tür ist geschlossen
4) Tür öffnet

Zwischen diesen Zuständen gibt es definiert Übergänge. Letztendlich musst du den Zustand abblinden und dieser kann genutzt werden um es z.B. in der Oberfläche anzuzeigen.
Du solltest auch auf eine strikte Trennung von Mechanik und Anzeige machen.

Beim Fahrstuhl selbst, gibt es genau so Staties.
1) Steht in einen Stockwerk
2) Fährt Aufwärts
3) Fährt Abwärts
4) Nothalt (zwischen Stockwerken)

Diese haben eine direkte Kopplung mit den Tür States.
Wäre doof wenn der Fahrstuhl Status 2-4 hat und die Türen nicht geschlossen sind.

Also schau dir mal das Pattern Zustandmaschine an:
http://de.wikipedia.org/wiki/Zustand_(Entwurfsmuster)

Horst_ 13. Jun 2013 12:36

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hallo,

um erstmal keinen Thread zu brauchen, ging auch das starten eines Timers, für jede Kabine getrennt.
Delphi-Quellcode:

function TTuer.schließen(...):bool;
 ...
begin
   ...
   tuerSchließend:= true;
   StarteTuerSchlieszTimer(100) ;
end;

procedure StarteTuerSchlieszTimer(deltaT:longint) ;
begin
  TuerSchlieszTimer.interval := deltaT;
  TuerSchlieszTimer.enabled := true;
end;

procedure TuerSchlieszTimer.OnTimer(....)
begin
  IF TuerSchliessend then
    begin
    TuerPos := TuerPos - deltaTuerPos;
    If TuerPos <= 0 then
      begin
      TuerPos := 0;
      TuerSchliessend := false;
      TuerSchlieszTimer.enabled := false; // Timer aus
      end;
    end
  else
    IF TuerOeffnend then
      begin
      TuerPos := TuerPos + deltaTuerPos;
        If TuerPos >= TuerMaxPos then
          begin
          TuerPos := TuerMaxPos
  ....
end;
Gruß Horst

Der schöne Günther 13. Jun 2013 12:40

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Darauf wollte ich hinaus - Dass eine Fahrstuhlkabine erst einmal eine Variable braucht, in welcher sie sich ihre Position merkt und diese bei Bedarf immer ein Stückchen hoch- oder heruntergesetzt wird. Und nicht von außen eine Methode schließeTür() mittendrin abbrechen ;-)

p80286 13. Jun 2013 13:04

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1218472)
Darauf wollte ich hinaus - Dass eine Fahrstuhlkabine erst einmal eine Variable braucht, in welcher sie sich ihre Position merkt und diese bei Bedarf immer ein Stückchen hoch- oder heruntergesetzt wird. Und nicht von außen eine Methode schließeTür() mittendrin abbrechen ;-)

du bist wohl schon länger nicht mehr mit einem Aufzug unterwegs gewesen?
Dieses Tür auf/Tür zu Knöpfchen ist doch sehr beliebt bei den Mitfahrern, die es eilig haben, die höflich sind.
Außerdem fehlt mir/hab ich übersehen die Lichtschranke in der Türe.

Meiner Meinung nach müßte es einen eigenen "Sicherungsthread" geben, der die notwendigen Sensoren/Signalgeber pollt oder aber eben auf die entsprechende Nachricht wartet.

Gruß
K-H

Der schöne Günther 13. Jun 2013 13:08

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Die Frage ist nur, ob wir nicht erst einmal anfangen sollten, von Zeigern und Strukturen runterzukommen, oder gleich gethreadete Türen reindrücken.

StuRic 13. Jun 2013 13:26

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Hi,

Zitat:

Zitat von Der schöne Günther (Beitrag 1218464)
Ich gehe wieder an den Anfang zurück und unterstelle dir, nicht wirklich zu wissen, was du konkret eigentlich machen möchtest.

In einem Lastenheft stehen die groben Anforderungen, die die Fahrstuhlsteuerung erfüllen muss. Alles Andere ist mir überlassen. Eine dieser Anforderungen ist, dass während die Türen geschlossen werden die Türen angehalten und wieder geöffnet werden können. Ich denke mal jeder kennt diesen Tür-Öffner im Fahrstuhl (z. B. so: <> ).

Zitat:

Zitat von Der schöne Günther (Beitrag 1218464)
Hast du eine nahende Deadline? Ich würde mir erst einmal fest machen, was das Ding eigentlich konkret können soll, und WIE es das können soll. Beispielsweise einen hoch- und herunterfahrenden Aufzug zeichnen (ebenso wie öffnende und schließende Türen) - Auf Knopfdruck kann der Benutzer dann das Öffnen und Schließen veranlassen und bsp. einen laufenden Öffne/Schließevorgang abbrechen.

Nen paar Tage hab ich schon noch Zeit :) Der normale Öffne/Schließevorgang ist schon implementiert und im herkömmlichen Sinne funktionstüchtig. Ebenso die Benutzeroberfläche erstellt... Wenn ich hier nicht meinen kompletten Code poste, dann eher weil es für 90% der Leute vermutlich uninteressant ist. Verbessert mich, wenn ich mich irre :wink:


Zitat:

Zitat von Horst_ (Beitrag 1218470)
Hallo,

um erstmal keinen Thread zu brauchen, ging auch das starten eines Timers, für jede Kabine getrennt.

An sowas Ähnliches hatte ich auch schon gedacht. Danke fürs Beispiel. Wenn es nicht irgendwie "eleganter" geht, werde ich es wie von dir vorgeschlagen lösen.

Zitat:

Zitat von generic (Beitrag 1218467)
Zwischen diesen Zuständen gibt es definiert Übergänge. Letztendlich musst du den Zustand abblinden und dieser kann genutzt werden um es z.B. in der Oberfläche anzuzeigen.
Du solltest auch auf eine strikte Trennung von Mechanik und Anzeige machen.
...
Also schau dir mal das Pattern Zustandmaschine an:
http://de.wikipedia.org/wiki/Zustand_(Entwurfsmuster)

Hm,...ich bin mir nicht sicher, ob ich dich richtig verstehe:
Ich möchte während der Zustandsänderung eingreifen. Daher helfen mir die vorgefertigten Zustände an dieser Stelle nicht weiter...oder meinst du ein Redefinieren der Zustände (z.B. Zwischenzustände)?

generic 14. Jun 2013 11:24

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Du kannst doch jederzeit eingreifen.
Hauptsache der Übergang ist erlaubt. So ein Zwischenstand ist doch "Tür geht zu".
Dieser Zustand dauert ja an bis die Tür vollständig zu ist oder jemand die Lichtschranke unterbricht oder den Tür auf Knopf drückt.
Bei den letzten beiden geht der Zustand in "Tür geht auf" über. Beim letzten Zustand, wird sich sicherlich der Zustand der Kabine ändern in "Fährt hoch" oder "Fährt runter" vorausgesetzt jemand hat ein Stockwerk gedrückt oder in einen Stockwerk wurde der Lift gerufen.

Übergänge werden immer durch Ereignisse ausgelöst. Um dann den Übergang zu finden, ist die Ereignisart und Regeln erforderlich.

Kleines Beispiel vielleicht. Diese Türanimation über einen z.B. Thread läuft ja nur so lange bis die Tür geschlossen/offen ist. Also ist in einen Thread Logik für mach den Türmotor an für schließen und warte bis der Endschalter (Tür zu) erreicht ist. Dann Motor aus. Fertig -> Ereignis Tür ist zu.

Die Bewegungen erfolgen ja auch asynchron. Du weißt ja nicht wie lange die Tür öffnet oder schließt. Wenn die Tür fahrt durch Knopf abgebrochen wird, verkürzen sich ja die Zeiten abhängig von der Türposition.




Fahrstühle habe übrigens einen Plan, wie die Anforderungen abgefahren werden.
Es wird immer nun in eine Richtung gefahren bis es keine Anforderungen mehr gibt aus Stockwerken, welche in Fahrrichtung liegen.

In sehr hohen Gebäuden gibt es dann auch noch ein Fahrplan Optimierer bzw. mehrere Kabinen in einen Schacht.
Diese Kabinen teilen sich dann optimiert die Fahrten.

Allerdings muss der Fahrgast vorher an einen Terminal sein Stockwerk sagen und er bekommt dann den Fahrstuhl mitgeteilt.

Sir Rufo 14. Jun 2013 12:05

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Der Fehler in der Umsetzung ist der, dass bei der Anweisung "Schließe die Tür" der komplette Vorgang abgearbeitet wird.
In der Praxis wäre es so, dass beim Drücken des Schließen-Knopfes alle Knöpfe ihre Funktion verlieren (blockiert sind), bis die Tür geschlossen ist.

Im Anhang habe ich mal ein kleines Projekt für eine Fahrstuhltür, die man auch im laufenden Betrieb wieder öffnen kann.

Basisklasse
Delphi-Quellcode:
  EElevator = class( Exception );

  TElevatorDoorState = ( edsClosed, edsClosing, edsOpening, edsOpen );

  TElevatorDoor = class( TProgressEntity )
  protected
    function GetPosition : Integer; virtual; abstract;
    function GetState : TElevatorDoorState; virtual; abstract;
  public
    // Nur zur Visualisierung (0-100)
    property Position : Integer read GetPosition;
    // Status
    property State :   TElevatorDoorState read GetState;
    // Befehle
    procedure Open; virtual; abstract;
    procedure Close; virtual; abstract;
  end;
und konkret
Delphi-Quellcode:
  TDumbElevatorDoor = class( TElevatorDoor )
  private
    // Öffnen-/Schließ-Geschwindigkeit in m/s
    FDirection : Extended;
    // Position der Tür in m (0m - 1m)
    FPosition : Extended;
  protected
    function GetState : TElevatorDoorState; override;
    function GetPosition : Integer; override;
    procedure Progress( const IntervalMS : Cardinal ); override;
  public
    procedure Open; override;
    procedure Close; override;
  end;

implementation

uses
  System.Math;

const
  cEpsilon = 0.001;

  { TDumbElevatorDoor }

procedure TDumbElevatorDoor.Close;
begin
  FDirection := - 0.3; // 0.3m/s Schließgeschwindigkeit
end;

function TDumbElevatorDoor.GetPosition : Integer;
begin
  Result := 100 - Round( FPosition * 100 );
end;

function TDumbElevatorDoor.GetState : TElevatorDoorState;
begin
  if FDirection > 0
  then
    Result := edsOpening
  else if FDirection < 0
  then
    Result := edsClosing
  else if SameValue( FPosition, 0, cEpsilon )
  then
    Result := edsClosed
  else if SameValue( FPosition, 1, cEpsilon )
  then
    Result := edsOpen
  else
    raise EElevator.Create( 'Fahrstuhltür defekt' );
end;

procedure TDumbElevatorDoor.Open;
begin
  FDirection := 0.5; // 0.5m/s Öffnen-Geschwindigkeit
end;

procedure TDumbElevatorDoor.Progress( const IntervalMS : Cardinal );
var
  LNewPosition : Extended;
begin

  LNewPosition := FPosition + FDirection / 1000 * IntervalMS;

  if LNewPosition >= 1
  then
    begin
      FPosition := 1;
      FDirection := 0;
    end
  else if LNewPosition <= 0
  then
    begin
      FPosition := 0;
      FDirection := 0;
    end
  else
    FPosition := LNewPosition;

end;

StuRic 15. Jun 2013 11:05

AW: dynamische Verwaltung von Objekten - Fahrstuhlsteuerung
 
Moin,

Zitat:

Zitat von generic (Beitrag 1218588)
Du kannst doch jederzeit eingreifen.
Hauptsache der Übergang ist erlaubt. So ein Zwischenstand ist doch "Tür geht zu".
Dieser Zustand dauert ja an bis die Tür vollständig zu ist oder jemand die Lichtschranke unterbricht oder den Tür auf Knopf drückt.

...

Übergänge werden immer durch Ereignisse ausgelöst. Um dann den Übergang zu finden, ist die Ereignisart und Regeln erforderlich.

Pinzip hab ich verstanden. Danke dir für die ausführliche Erklärung :)

Zitat:

Zitat von Sir Rufo (Beitrag 1218595)
Im Anhang habe ich mal ein kleines Projekt für eine Fahrstuhltür, die man auch im laufenden Betrieb wieder öffnen kann.

Vielen Dank für die Mühe! Ich werde mit Sicherheit nen paar Tage brauchen bis ich (fast) alle Details verstanden hab.
Bis denn!


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz