Startseite ¦  was ist neu ¦  programmier tips ¦  indy artikel ¦  intraweb artikel ¦  informationen ¦  links ¦  interviews ¦  sonstiges
kylix ¦  tutorials ¦  online shop ¦  fotos ¦  Add&Win Gewinnspiel


Willkommen Gast. Bitte einloggen oder registrieren.
04.02.2012, 09:08:44
Übersicht Hilfe Suche Einloggen Registrieren

+  SwissDelphiCenter Forum
|-+  German Forums
| |-+  Einsteiger Forum
| | |-+  Eigene Datentypen verschachteln
« vorheriges nächstes »
Seiten: [1] Drucken
Autor Thema: Eigene Datentypen verschachteln  (Gelesen 3981 mal)
Thomas
Newbie
*
Offline Offline

Beiträge: 30


« am: 22.10.2008, 17:55:42 »

Hallo Zuammen,

ich benötige für eine Schnittstelle zwischen zwei DV-Systemen einen Datentype mit 1 Hauptdatensatz und x Unterdatensätzen.

Beispiel:

Code:
Type
  Haupt = Record
    Feld1 : String;
    Feld2 : Integer;
    Feld3 : String;
    Feld4 : String;
    Feld5 : Array[1..x] of Unter;
  end;

  Unter = Record
    Daten1 : string;
    Daten2 : String;
    Daten3 : String;
  end;

Mein Wunsch ist jetzt, daß ich für das Feld5 keine feste Anzahl im Vorfeld angebe, sondern diese dynamisch anlegen bzw. löschen kann.

z.B. mit: haupt.feld5.add und haupt.feld5(i).delete
oder so ähnlich.

Kann mir jemand erklären, wie man so etwas programmiert?

Gruß aus Köln
Thomas
« Letzte Änderung: 22.10.2008, 18:21:31 von Thomas » Gespeichert
grenzgaenger
Global Moderator
Full Member
*****
Offline Offline

Beiträge: 232


« Antworten #1 am: 22.10.2008, 23:00:44 »

Hallo Thomas,

wo liegt das problem und woher kommt die schnittstelle (lesend oder schreibend)?

da deine datendefinition, leider, unvollständig war, antworte ich dir mit eben so einer, wobei ich auch meine kristallkugel nicht mit bei habe...

Code:
Type
  Unter = Record
    Daten1 : string;
    Daten2 : String;
    Daten3 : String;
  end;
  Haupt = Record
    Feld1 : String;
    Feld2 : Integer;
    Feld3 : String;
    Feld4 : String;
  end;

hier in deinem fall, einfach umstellen von unter und haupt. wie oft du den unter brauchst, musst du wo anders mitschreiben...

das schreiben kannst dann einfach in einer verschachtelten schleife durchführen...

Code:
for i := 0 to hauptlist.count -1 do
 begin
 schreibe(haupt[i]);
 for j := 0 to hauptlist.items[i].unterlist.count - 1 do
  schreibe(unter[i, j]);
 

das müsst funktionieren :-)

wenn du mehr wisen willst, brauchen wir da doch etwas mehr informationen ...

grüsse
 GG
Gespeichert
Thomas
Newbie
*
Offline Offline

Beiträge: 30


« Antworten #2 am: 23.10.2008, 06:58:43 »

Hallo Grenzgänger,

sorry für meine unpräzise Fragestellung.

Hier die (hoffentlich) genauere Erklärung:
Ein Meßgerät liefert eine Textdatei mit den Ergebnissen. Dabei stellt jede Zeile der Textdatei einen Messpunkt mit mehreren Messungen dar. Zuerst kommen, mit Semikolon getrennt, die Kopfdaten zum Messpunkt und die Anzahl an Messergebnissen. Danach kommen die Messergebnisse, wobei die einzelnen Angaben zu einem Messergebnis mit Komma getrennt sind, die einzelnen Messungen wieder mit Semikolon.
Beispiel:
Köln;2008-10-22;3;Temp,23.6,Grad;Feucht,60.2,Prozent;Druck,1013.25,hPa;
Bonn;2008-10-18;4;Temp,22.8,Grad;Feucht,58.9,Prozent;Druck,1011.71,hPa;Nieder,22,mm;

Der gewünschte Datentyp soll somit folgenden Aufbau haben:
Zitat
Type
  Ergebnis = Record
    Typ : string;
    Wert : Double;
    Einheit : String;
  end;
  Messung = Record
    Ort : String;
    Datum : TDateTime;
  end;

Ich weiß im Vorfeld nicht, wieviele Messungen ich habe und jede Messung kann eine unterschiedliche Anzahl an Ergebnissen haben. Somit muß das Array Messungen variable sein und ich muß diesen Messungen eine vorher unbekannte Anzahl an Ergebnissen zuordnen können.

Ich wünsche mir in etwa folgende Mechanismen:

Anlegen einer neuen Messungen: Messungen.Add
Abfragen der Anzahl an Messungen: Messungen.Count
Anlegen eines neuen Ergebnis: Messungen(x).Ergebnisse.Add
Abfragen der Anzahl an Ergebnissen: Messungen(x).Ergebnisse.Count

Im obigen Beispiel also:
Messungen.Count -> 2
Messungen(1).Ergebnisse.Count -> 3
Messungen(2).Ergebnisse.Count -> 4
Messungen(2).Ergebnisse(3).Wert -> 1011.71

Mein Problem ist jetzt, daß ich nicht weiß, wie man solche variablen Datentypen definiert, verschachtelt und die gewünschten Mechanismen programmiert. Ob der Index mit 0 oder, wie im Beispiel, 1 beginnt, ist dabei egal.

Nachdem ich alle Messungen eingelesen habe, sollen diese zur Auswahl angeboten werden und nach Selektion in eine Datenbank geschrieben werden.

Ich hoffe, ich habe mein Problem und meine zu schließende Wissenslücke präzise dargestellt.

Gruß aus Köln
Thomas
« Letzte Änderung: 23.10.2008, 07:08:37 von Thomas » Gespeichert
grenzgaenger
Global Moderator
Full Member
*****
Offline Offline

Beiträge: 232


« Antworten #3 am: 23.10.2008, 08:15:22 »

Hallo Thomas,

jetzt wird das Problem schon klarer. An deiner Stelle würde ich Objekte, anstatt Records nehmen und diese in einer ObjectList verwalten. Bei diesen kannst Du dann auch "Intelligenz" hinzufügen.

Beispiel aufbau:
type
 TMesspunkt = class
    Typ : string;
    Wert : Double;
    Einheit : String;
 end;
 TListMesspunkte = class(tObjectList)
   constructor Create;
   destructor Destroy;   
   //und zu jeder Liste eine Property
   property items[i: index]: tMesspunkt read GetMesspunkt write SetMesspunkt;
 end;
 TLocationList = class(TObjectList)
   Ort : String;
   Datum : TDateTime;
   FMesspunkte: TListMesspunkte;
   constructor Create;
   destructor Destroy;   
 end;
 TTempList = class(TObjectList)
   FLocationList: TLocationList; //List of all Locations and Temp.
   constructor Create;
   destructor Destroy;
 end;

implementation
constructor TListMesspunkte.Create;
begin
 inherited;
 FLocationlist := TLocationList.create;
end;

Destructore TListMesspunkte.destroy;
begin
 fLocationList.free;
 inherited;
end;
constructor TTempList.Create;
begin
 inherited;
 FLocationlist := TLocationList.create;
end;

Destructore TTempList.destroy;
begin
 fLocationList.free;
 inherited;
end;
constructor TListMesspunkte .Create;
begin
 inherited;
 FLocationlist := TLocationList.create;
end;

Destructore TListMesspunkte .destroy;
begin
 fLocationList.free;
 inherited;
end;


Zu jeder Liste setzt du dann noch eine Property ein. In der Liste nimmst du deine Zeile entgegen, bereitest diese auf und gibst diese an deine Liste. die TObjectList verwaltet diese dann und du kannst auf die einzelnen einträge über Items[myIndex] zugreiffen.

für jede Datenzeile musst du dann nur noch eine kleine schleife machen, z.B. wie hier im Beispiel: http://www.swissdelphicenter.ch/de/forum/index.php/topic,12172.0.html

und deine einzelnen datenpunkte aufnehmen in einer kleinen schleife.

mit der Objekctlist, biste flexibel in deiner datenmenge und sie verwaltet auch gleich den speicher selbst.

<HTH> GG

Gespeichert
Thomas
Newbie
*
Offline Offline

Beiträge: 30


« Antworten #4 am: 23.10.2008, 21:51:07 »

Hallo Grenzgänger,

leider habe ich es nur teilweise verstanden, da ich noch nie mit TObjectList gearbeitet habe.

Ich habe folgende Unit erstellt:

Code:
unit Proben;

interface

uses
  Contnrs;

type
  TErgebnis = class
    Typ : string;
    Wert : Double;
    Einheit : String;
  end;
  TErgebnisListe = class(TObjectList)
    protected
      Function     GetErgebnis(Index: Integer): TErgebnis;
      Procedure    SetErgebnis(Index: Integer; Objekt: TErgebnis);
    public
      constructor  Create;
      destructor   Destroy;
      property     Items[i: Integer]: TErgebnis read GetErgebnis write SetErgebnis;
  end;
  TProbe = class
    Probennummer : String;
    Datum        : TDateTime;
    Ergebnis     : TErgebnisListe;
  end;
  TProbenListe = class(TObjectList)
    protected
      Function     GetProbe(Index: Integer): TProbe;
      Procedure    SetProbe(Index: Integer; Objekt: TProbe);
    public
      constructor  Create;
      destructor   Destroy;
      function     Add(AObject:TProbe):Integer;
      property     Items[i: Integer]: TProbe read GetProbe write SetProbe;
  end;

implementation

function TErgebnisListe.GetErgebnis(Index: Integer): TErgebnis;
begin
  Result := TErgebnis(inherited Items[Index]);
end;

procedure TErgebnisListe.SetErgebnis(Index: Integer; Objekt: TErgebnis);
begin
  inherited Items[Index] := Objekt;
end;

function TProbenListe.GetProbe(Index: Integer): TProbe;
begin
  Result := TProbe(inherited Items[Index]);
end;

procedure TProbenListe.SetProbe(Index: Integer; Objekt: TProbe);
begin
  inherited Items[Index] := Objekt;
end;

constructor TProbenListe.Create;
begin
  inherited;
  // Ergebnis := TErgebnisListe.Create;
end;

destructor TProbenListe.destroy;
begin
  // Ergebnis.Free;
  inherited;
end;

function TProbenListe.Add(AObject:TProbe):Integer;
begin
  result:=inherited Add(AObject);
end;

constructor TErgebnisListe.Create;
begin
  inherited;
//  TErgebnisListe := TErgebnisListe.Create;
end;

destructor TErgebnisListe.destroy;
begin
//  TErgebnisListe.Free;
  inherited;
end;

end.

Im Hauptprogramm habe ich dann diese Unit eingebunden und folgenden Button erstellt:

Code:
procedure TFrmProben.Button1Click(Sender: TObject);
var
  Probe : TProbe;
begin
  Probe.Probennummer := '1234567890';
  Probe.Datum := Now;
  _Proben.Add(Probe);
  ShowMessage(IntToStr(_Proben.Count));
end;

die Variable
  _Proben : TProbenList;
ist global definiert und
  _Proben.Create
erfolgt in der Initialisierungsroutine.

Nur funktioniert dies nicht ... bricht beim Befehl _Proben.Add mit einer Schutzverletzung ab ... und ich habe keine Idee ...

Gruß aus Köln
Thomas
« Letzte Änderung: 23.10.2008, 21:55:07 von Thomas » Gespeichert
grenzgaenger
Global Moderator
Full Member
*****
Offline Offline

Beiträge: 232


« Antworten #5 am: 23.10.2008, 22:03:30 »

tja, dein problem liegt hier:
Code:
procedure TFrmProben.Button1Click(Sender: TObject);
var
  Probe : TProbe;
begin
  Probe.Probennummer := '1234567890'; //<<< hier
  Probe.Datum := Now;
  _Proben.Add(Probe);
  ShowMessage(IntToStr(_Proben.Count));
end;


diese routine müsst so aussehen:
Code:
procedure TFrmProben.Button1Click(Sender: TObject);
var
  Probe : TProbe;
begin
  Probe := TProbe.create;
  Probe.Probennummer := '1234567890'; //<<< hier
  Probe.Datum := Now;
  c.Add(Probe);
  ShowMessage(IntToStr(_Proben.Count));
end;
[/tt]

du musst dein objekt zuvor initialisieren resp. speicher  zuweisen, bevor du es verwenden kannst.



genauso ergeht's deinen listen... im form.create musst du speicher reservieren:

Code:
_proben := tProbenlist.create;

und im form.destroy musst du deine liste wieder freigeben...

Code:
if _proben <> NIL then FreeAndNIL(_proben);

dann sollte es funktionieren. :-) die liste kümmert sich selbsttätig darum, dass alle untergeordneten objekte resp. listen, wieder freigegeben werden.

btw: lohnt sich ein blick in die OH zu TObjectList  -_- hier ist schon einiges vordefiniert auch einiges, was man brauchen kann. das mit dem property items, ist nur eine erleichterung, damit du nicht ständig casten musst und deine liste (etwas) typsicher ist...

<HTH> GG
Gespeichert
Thomas
Newbie
*
Offline Offline

Beiträge: 30


« Antworten #6 am: 09.11.2008, 22:47:40 »

Hallo Grenzgänger,

ich habe letzte Woche endlich die Zeit gefunden, daß Programm zuende zu schreiben.

Danke für Deine Tips und Gruß aus Köln

Thomas
Gespeichert
Seiten: [1] Drucken 
« vorheriges nächstes »
Gehe zu:  


Einloggen mit Benutzername, Passwort und Sitzungslänge

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006, Simple Machines LLC Prüfe XHTML 1.0 Prüfe CSS