Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Einer Routine einen beliebigen Record übergeben (https://www.delphipraxis.net/30692-einer-routine-einen-beliebigen-record-uebergeben.html)

Luckie 28. Sep 2004 01:04


Einer Routine einen beliebigen Record übergeben
 
Folgendes Szenario:
Um Einstellungen in eine Ini-Datei zu speichern erstelle ich mir immer einen Record:
Delphi-Quellcode:
TSettings = packed record
  ...: ...;
  ...: ...;
  ...: ...;
end;
Diesen Record fülle ich und übergeben ihn dann an eine Routine SaveSettings:
Delphi-Quellcode:
procedure SaveSettings(IniFile: String; Settings: TSettings);
Das Gegenstück zum Laden dazu sieht folgendermaßen aus:
Delphi-Quellcode:
function LoadSettings(IniFile: String; var Settings: TSettings): Boolean;
Jetzt ist es ja so, das für jedes Projekt ein eigener Record definiert werden muss, weil man eben immer was anderes Speichern will. OK. Aber leider muss man auch immer wieder die obigen Routinen anpassen. Kann man jetzt irgendwas konstruieren, dass man jeweils nur den Record entsprechend anpasst und den Rest zum Speichern und Laden so lassen kann? Würde einem viel Arbeit abnehmen. Hat da jemand eine Idee oder ansatz, wie man das machen könnte?

Dax 28. Sep 2004 06:27

Re: Einer Routine einen beliebigen Record übergeben
 
Wenn du im Record nie Strings/Pointer (dazu zählen auch Klassen) benutzt, kannst du einfach
Delphi-Quellcode:
TFileStream.Write(MyRecord, sizeof(MyRecord));
schreiben.

Dax 28. Sep 2004 12:49

Re: Einer Routine einen beliebigen Record übergeben
 
:oops: Korrektur: Du kannst bei dieser Methode schon Strings verwenden, aber nur die ShortStrings in der Form MyString: String[x] mit 0 < x < 256.
Du könntest aber auch eine "Memory-Map" des Records anlegen, die dir sagt, wo strings sind, wo Pointer sind (zusammen mit ihren Typen).

Aber Klassen kannst du NIE verwenden, wenn mich mein Kenntnisstand nicht täuscht. ;)
Es sei denn, du fügst deiner Klasse Methoden hinzu, die aus den Daten der Klasse einen Stream erzeugen, in dem allen Daten enthalten sind, sowie eine Methode, die das ganze dann auch wieder liest.

Luckie 28. Sep 2004 13:05

Re: Einer Routine einen beliebigen Record übergeben
 
Das ist noch nicht so das, was ich mir vorstelle.

Nightshade 28. Sep 2004 13:26

Re: Einer Routine einen beliebigen Record übergeben
 
Ich würd das Ini-File komplett in eine Stringliste laden.

Bei nur einer Section kannst du dann einfach mit

Delphi-Quellcode:
Pfad := Settings.Values['DatanbankPfad'];
Auf die Variablen zugreifen.

Wenn du mehrere Sections hast Den String einfach
Delphi-Quellcode:
 String := Section + '#' + Name + '#' + Value;
zusammen bauen und ne passende Function für bauen um das auszulesen.

Sonst mit Records fällt mir da nichts ein...

shmia 28. Sep 2004 17:08

Re: Einer Routine einen beliebigen Record übergeben
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Luckie
Kann man jetzt irgendwas konstruieren, dass man jeweils nur den Record entsprechend anpasst und den Rest zum Speichern und Laden so lassen kann? Würde einem viel Arbeit abnehmen. Hat da jemand eine Idee oder ansatz, wie man das machen könnte?

Wenn du dich von normalen Records verabschiedest und stattdessen etwas komplizierteres verwendest, dann geht das.
Ich habe mir mal vor einiger Zeit ein "typisiertes Variant-Array" gebastelt.
Man hat also ein Array vom Datentyp Variant wobei jedes Element entweder über einen Namen oder einen Indez angesprochen werden kann.
Bei der Initialisierung wird zusätzlich zum Namen und Index auch noch ein Datentyp mitgegeben.
Der Zugriff auf die Daten sieht z.B. so aus:
Delphi-Quellcode:
 
const
   list:array [0..8] of TVAitem =
   (
   (name:'ArtikelNr';   vartype: varString),
   (name:'ArtikelName'; vartype: varString),
   (name:'EAN13';       vartype: VarString),
   (name:'Menge';       vartype: varDouble),
   (name:'MengeUnit';   vartype: varString),
   (name:'BruttoGewicht';vartype: varDouble),
   (name:'NettoGewicht'; vartype: varDouble),
   (name:'AuftragsNr';   vartype: varString),
   (name:'EquipmentNr';   vartype: varString)
   );
begin
   va := TTypedVariantArray.Create(list);

   va.ValueByName['ArtikelNr']  := '4711';
   va.ValueByName['Menge']      := 150.0;
Da man die Anzahl der Elemente und alle Namen abfragen kann, ist es kein Problem die Daten
in eine INI-Datei zu speichern.

choose 28. Sep 2004 20:13

Re: Einer Routine einen beliebigen Record übergeben
 
Was spricht gegen den Einsatz von Klassen und der RTTI, so wie es der Streaming-Mechanismus von Delphi macht? Lösungen, wie Typen, Namen und Werte von published properties ermittelt und letztere gesetzt werden, solltest Du im Web finden.

Es ist dazu nicht notwendig, Deine Klasse von TPersistent erben zu lassen, das Kompilieren mit dem Schalter {$M+} Deiner jeweiligen Klasse, besser noch, einer schlanken Basisklasse, die Du dann auch für die Signatur von anderen Methoden verwenden könntest, reicht (auch für die Erben) vollkommen aus...

negaH 28. Sep 2004 21:39

Re: Einer Routine einen beliebigen Record übergeben
 
Delphi-Quellcode:
type
 TAbstractSettings = class(TObject)
 protected
   procedure Save(Stream: TStream); virtual; abstract;
   procedure Load(Stream: TStream); vietual; abstract;
 end;

 TTestSettings = class(TAbstractSettings)
 private
   FLeftPos: Integer;
   FRightPos: Integer;
 public
   property LeftPos..... bla bla usw.
 end;
Obiges Klassenkonstrukt ist nichts anderes als ein Record, ein Record mit Properties, virtuellen Methoden, Events, Typsicherheit, Zugriffsmethoden etc.pp.
Was spricht also für generische Records und was spricht gegen Klassen ?

Falls du wirklich ganz ganz generische Records benutzen willst, also KEINE vollständigen Objecte bei denen man Methoden selber schreiben will so kann man denoch Klassen dazu benutzen. Man deklariert einfach eine X'beliebige Klasse abgeleitet von TObject und alle Felder als published. Die globale und procedurale Lade/Speicher Routine kann nun mit Hilfe der RTTI dieser Klasse dynamisch zur Laufzeit die Felder und deren Typen ermitteln und deren Inhalte laden und speichern.

Gruß Hagen

Luckie 29. Sep 2004 13:50

Re: Einer Routine einen beliebigen Record übergeben
 
Ich habe mich noch gar nicht irgendwie festgelegt. Das mit dem Record war nur zur Verdeutlichung gedacht.

Ich werde mir mal eure Vorschläge durch den Kopf gehen lassen.

Nightshade 29. Sep 2004 22:29

Re: Einer Routine einen beliebigen Record übergeben
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab mir die Sache mit dem RTTI und so mal angeschaut...

Benutz es, oder leite was draus ab, oder verbesser es, oder lass es :lol:

Bei mir ist auf jeden Fall das hier herausgekommen :


TSettings so deklarieren wie man es braucht :

Delphi-Quellcode:
type TSettings = class(TComponent)
   private
    Ff: byte;
    Fg: char;
    Fb2: double;
    Fa1: integer;
    FPfad: string;
    Fe: word;
    Fd: string;
    Fh: boolean;
  protected
  public
  published
    property Pfad : string read FPfad write FPfad;
    property a1 : integer read Fa1 write Fa1;
    property b2 : double read Fb2 write Fb2;
    property d : string read Fd write Fd;
    property e : word read Fe write Fe;
    property f : byte read Ff write Ff;
    property g : char read Fg write Fg;
    property h : boolean read Fh write Fh;
end;
und dann speichern oder laden...

Delphi-Quellcode:
uses SettingsVorlage;

procedure TForm1.BitBtn1Click(Sender: TObject);
var t : TSettingsVorlage;
begin
  t := TSettingsVorlage.Create(self);
  t.Settings.d := 'Hallo';
  t.Settings.Pfad := 'Welt';
  t.SaveToFile(Pfad+'Testfile.dat');
//   t.SaveToINIFile(Pfad+'Testfile.ini');
//   t.SaveToRegistry(HKEY_LOCAL_MACHINE ,'Software\YDB-Soft\Testfile');
  t.free;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:01 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