Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi [Records] Codeoptimierung bei Übergabetypen (https://www.delphipraxis.net/30164-%5Brecords%5D-codeoptimierung-bei-uebergabetypen.html)

Luckie 22. Sep 2004 11:12

Re: [Records] Codeoptimierung bei Übergabetypen
 
adata ist vom Typ TData. TData ist ein Record mit den Feldern FGBez und FMonat. Die methode GetNodeData liefert einen Pointer zurück. Das mal dazu wie es aussieht.

Erstmal hast du vergessen ein Feld anzugeben in dem die Daten abgelegt werden sollen:
Code:
adata[b].FGBez[/b] := ...;
Und zweitens ist ein Record nicht zu einem Pointer kompatibel, wie du es geschrieben hast:
Code:
adata := MyPointer;
Das hingegen würde gehen:
Delphi-Quellcode:
type
  TData = record
    ...;
  end;
  PData = ^TDate;

var
  adata: PData;

...

  adata := PData(MyPointer);
Also überdenk noch mal, was du eigentlich machen willst.

Igotcha 22. Sep 2004 11:47

Re: [Records] Codeoptimierung bei Übergabetypen
 
Zitat:

Also überdenk noch mal, was du eigentlich machen willst.
Das weiss ich schon, deshalb fragte ich ja hier ;-) Wie gesagt, meine Anwendung läuft, ich möchte sie aber in der Codegröße in Bezug auf die Records schrumpfen (u.a. auch wegen der Pflege).

Zitat:

adata ist vom Typ TData. TData ist ein Record mit den Feldern FGBez und FMonat. Die methode GetNodeData liefert einen Pointer zurück. Das mal dazu wie es aussieht.

Erstmal hast du vergessen ein Feld anzugeben in dem die Daten abgelegt werden sollen:
Code:
adata[b].FGBez[/b] := ...;

Nicht notwendig, da der Kompiliervorgang schon vorher abbricht. Die Zeile hätte ich noch hinschreiben können, ist aber unnötig.

Zitat:

Das hingegen würde gehen:
Delphi-Quellcode:
type
  TData = record
    ...;
  end;
  PData = ^TDate;

var
  adata: PData;

...
adata := PData(MyPointer);

Wenn ich das recht überblicke, dann würde ich damit wieder genau am Anfang meines Problems stehen denn:

Delphi-Quellcode:
type
  TData = record
    ...;
  end;
  PData = ^TDate;

var
  Istdaten: PData;
  Plandaten: PData;
  Prognosedaten: PData;
Müsste in allen drei Fällen auf die gleichen Inhalte zeigen, wenn ich das richtig sehe. Und bei

Delphi-Quellcode:
type
  TData = record
    ...;
  end;
  PData1 = ^TDate;
  PData2 = ^TDate;
  PData3 = ^TDate;
var
  Istdaten: PData1;
  Plandaten: PData2;
  Prognosedaten: PData3;
bin ich wieder bei meiner Ausgangsfrage, denn ich müsste in meinen Routinen entweder PData1 oder PData2 oder PData3 benutzen und hätte dann wieder drei Varianten, um den Pointer auf den richtigen Record zu setzen:

Delphi-Quellcode:
var
  myData: IstDaten;
begin
myData:=atree.GetNodeData(myNode); oder

var
  myData: Plandaten;
begin
myData:=atree.GetNodeData(myNode); oder

var
  myData: Prognosedaten;
begin
myData:=atree.GetNodeData(myNode); oder
Ich möchte garantiert nicht unhöflich erscheinen, aber ist das eigentliche Problem eigentlich erkannt worden? Jeder VTV hat seinen eigenen Record, da er eigene Daten enthält. Ein VTV zeigt die IstDaten, der zweite die Plandaten, der dritte die Prognosedaten an. Die Records sind in der Struktur alle gleich - das haben wir ja auch hinbekommen. Der Zugriff auf die Daten (neu, lesen, schreiben) steuert der VTV, indem beim schreiben oder lesen an den VTV die Aufforderung gesendet wird "Gib mir bitte einen Zeiger auf den Recordeintrag entweder auf die Ist-, Plan- oder Prognosedaten. Erst wenn ich diesen Zeiger habe, komme ich an die Daten des Recordsatzes. Dies erledigt die VTV-Methode "GetNodeData". Dies hängt damit zusammen, dass der VTV über die Daten, die er verwaltet nichts weiss, sondern nur pro Node eine Verknüpfung (sprich also nur die Nummer auf einen Record-Satz, nicht aber die Art des Record-Typs) auf einen Recordeintrag in Form einer verketteten Liste hat.

Um nicht, wie es im Moment existiert, für jeden VTV eigene Routinen schreiben zu müssen, die sich nur darin unterscheiden, auf welche Daten er zugreift, habe ich nach einer Vereinfachung gesucht. Und zwar in der Form, dass ich für alle drei VTV pro Aufgabe nur eine Routine schreibe, der ich mitteile a) welcher VTV überhaupt angesprochen wird und b) auf welche Recorddaten sich die Manipulation bezieht.

Für das Beispiel einer Summenbildung wäre das z.B.:

Delphi-Quellcode:
procedure BildeSumme(TreeViewIstDaten, IstDatenrecord)
procedure BildeSumme(TreeViewPlanDaten, PlanDatenrecord)
procedure BildeSumme(TreeViewPrognoseDaten, PrognoseDatenrecord)
Ich muss aber (wie schon mehrfach gesagt), sobald ich die Daten bearbeiten möchte, angeben, welche Daten bearbeitet werden sollen. Und diese Daten kann ich mir nur mit der Methode "GetNodeData" holen - das Ergebnis ist ein Zeiger auf den entsprechenden Record-Eintrag, abhängig vom dem "Node", der ausgewählt wurde. Die Variable muss aber vom richtigen Record-Typ (ist, Plan, Prognose) sein.

Um mal bei meiner Ursprungsdeklaration zu bleiben, folgendes (unsinniges) Beispiel ist möglich:

Delphi-Quellcode:
var
  myIst: pIstdaten;
  myPlan: pPlandaten;
begin
  myIst:=TreeviewIst.GetNodeData(Node);
  myPlan:=TreeviewIst.GetnodeData(Node);
In diesem Fall hätte ich mit der selben Methode des VTVs für IstDaten einen Zeiger bekommen auf meine Plan- und meine IstDaten (sagen wir mal einen Zeiger auf jeweils den zweiten Record ). Dies kommt daher, da der VTV nichts über die Art der Daten, die er verwaltet weiss.

Und genau das, also welche Art des Records bearbeitet werden soll, möchte ich als Parameter übergeben. Dieser Übergabeparamteter muss aber ein Pointer auf den richtigen Record (Ist-, Plan- oder Prognosedaten-Record) sein:

Delphi-Quellcode:
BildeSumme(TIST, pIstDaten)
BildeSumme(TPLAN, pPlanDaten)
BildeSumme(TPROGNOSE, pPrognoseDaten)

und dann sollte so etwas in der Art in der Procedure stehen:

procedure BildeSumme(atree: TVirtualStringTree; adata: ???)
begin
    adata:=atree.GetNodeData(Node);
    adata.FBez:='Test';
    etc.
end;
Gruß Igotcha

scp 22. Sep 2004 12:40

Re: [Records] Codeoptimierung bei Übergabetypen
 
Also nach wie vor sollte dies die richtige Lösung sein:
Delphi-Quellcode:
type
  TData = record
    ...;
  end;
  PData = ^TDate;

var
  Istdaten: PData;
  Plandaten: PData;
  Prognosedaten: PData;

procedure BildSumme(atree: TVirtualStringTree; var adata: PData)
begin
    adata:=atree.GetNodeData(Node);
    adata.FBez:='Test';
    etc.
end;

begin
  BildeSumme(TreeIST, IstDaten);
  BildeSumme(TreePLAN, PlanDaten);
  BildeSumme(TreePROGNOSE, PrognoseDaten);
end;
Was meinst du denn mit
Zitat:

Zitat von Igotcha
Müsste in allen drei Fällen auf die gleichen Inhalte zeigen, wenn ich das richtig sehe.

? Wenn du drei Variablen deklariert hast kannst du diese auch auf drei verschiedene Inhalte zeigen lassen. Das hat nichts damit zu tun, ob die jetzt alle PData heissen oder eben PIstData PPlanData usw.
Und wenn du unterscheiden können willst, aus welchem der drei VTVs ein Record ursprünglich kam, dann brauchst du im record ja nur einen Eintrag hinzufügen, etwa so:
Delphi-Quellcode:
type
  TMyRecordOrigin = (roPlan, roIst, roProgrnose);

type
  TData = record
    ...;
    Origin : TMyRecordOrigin;
  end;

Igotcha 22. Sep 2004 13:41

Re: [Records] Codeoptimierung bei Übergabetypen
 
Danke danke danke, jetzt habe ich ein neues Problem ;-)

Es funktioniert wunderbar, nur kann ich mir jetzt überhaupt nicht mehr erklären wieso :shock:

Delphi-Quellcode:
type
  TData = record
  FBez: String;
  FMonat: array [0..1] of double;
  end;
  PData = ^TData;

...

var
  Istdaten: PData;
  Plandaten: PData;
  Prognosedaten: PData;
...

procedure TForm1.BildeSumme(atree: TVirtualStringTree; var adata: PData; aString: String);
var
  myNode: PVirtualNode;
begin
      aTree.Clear;
      aTree.NodeDataSize:=sizeof(TData); // Dies ist die einzigste "Beziehung", die zwischen einem VTV und "Art der Daten" überhaupt auftaucht - diese Anweisung muss auch nur einmal im Programm pro VTV auftauchen
      myNode:=atree.AddChild(nil);
      atree.BeginUpdate;
      adata:=atree.GetNodeData(myNode);
      adata.FBez:=aString; // dient nur zum Testen, ob tatsächlich die richtigen Records angesprochen werden
      adata.FMonat[0]:=1000;
      adata.FMonat[1]:=2000;
      atree.EndUpdate;
end;

procedure TForm1.est11Click(Sender: TObject);
begin
    // Genauso wollte ich es haben :-)
    BildeSumme(TIST, IstDaten,'Ist');
    BildeSumme(TPLAN, Plandaten,'Plan');
end;
Hier wird mir schon etwas mulmig. Warum greift er auf den richtigen Record-Typ zu?

Delphi-Quellcode:
procedure TForm1.TISTFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
var
  myNode: PData;
begin
  myNode:=TIST.GetNodeData(Node);
  ShowMessage(myNode.FBez); // Anzeige "Ist"
end;

procedure TForm1.TPLANFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
var
  myNode: PData;
begin
  myNode:=TPlan.GetNodeData(Node);
  ShowMessage(myNode.FBez); // Anzeige "Plan"
end;
Und hier wird mir ganz schwummerig ;-) Ich habe beiden Treeviews (TIST, TPLAN) die gleiche Ereignis-Routine zugewiesen (dient zur Anzeige der Inhalte):

Delphi-Quellcode:
procedure TForm1.TISTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
   myData : PData;
begin
  myData:=Sender.GetNodeData(node);

  if TextType=ttNormal then
  begin
    case Column of
      0: CellText:=myData.FBez;
      1: CellText:=floattostr(myData.FMonat[0]);
      2: CellText:=floattostr(myData.FMonat[1]);
  end;
  end;
end;
Ich kann mir das nur so erkären, dass der VirtualTreeview (der ja wie gesagt selbst die Daten nicht hält) durch die Methode "GetNodeDataSize" nicht nur die Grösse des Records, sondern anscheinend auch ein Verweis auf den Record anlegt.

Vielen Dank und Gruß
Igotcha

... der jetzt wohl einige Tage seinen Code dahingehend anpassen wird...

scp 22. Sep 2004 13:52

Re: [Records] Codeoptimierung bei Übergabetypen
 
Der VTV "kennt" den Inhalt der Daten nicht, er verwaltet sie aber. Deshalb musst du ja auch einmal die Grösse angeben ( SizeOf(TData) ). Der VTV reserviert dann den Speicher und gibt bei GetNodeData() dann den Pointer auf den Speicherbereich zurück.

oki 22. Sep 2004 14:55

Re: [Records] Codeoptimierung bei Übergabetypen
 
Hi Igotcha,

dein Verständnisproblem ist einfach zu erklären.

Du denkst immer noch, dass deine Funktion PData-Typen mit spezifischen Werten gleichsetzt. das ist aber nicht so.

Ich geb dir mal ein einfaches Beispiel:

Du willst drei Autos mit unterschiedlichen Fahrern haben, wobei die Autos alle vom gleichen Typ sind.
Alles gleich, Farbe, Motor ... usw.

Dieser Autotyp heißt jetzt nicht BMW oder so, sondern PData.

Du vergibst drei Stück davon mit drei unterschiedlichen Kennzeichen.

Jetzt sagst du einem Freund er soll alle Autos vom Typ PData (BMW) anhalten und fragen wie die Fahrer heißen.

Somit hast du ihm nicht gesagt er soll das Auto mit dem Kennzeichen x anhalten und das Auto mit dem Kennzeichen y usw. sondern eben Typbezogen. Da er weiß wo die Fahrer sitzen kann er gar nichts falsch machen, da die Typen ja identisch sind. Nur die Inhalte an der richtigen Stelle sind unterschiedlich. Und nur darum geht es dir.

Somit sind deine 3 Autos zwar dreimal da, aber alle vom gleichen Typ.

Somit kannst du deine Funktion "abstrahieren" (wenn ich mal so sagen darf). Welcher Record übergeben wird ist wurst, hauptsache der Typ stimmt und somit der Zugriff auf die richtige Stelle.

Die Deklaration:

procedure BildSumme(atree: TVirtualStringTree; var adata: PData)


ist somit ausreichend. Hier kannst alle Variablen vom Typ PData übergeben und es kommt immer das richtige zurück.

Gruß oki

Igotcha 22. Sep 2004 15:02

Re: [Records] Codeoptimierung bei Übergabetypen
 
Zitat:

Zitat von oki
...ist somit ausreichend. Hier kannst alle Variablen vom Typ PData übergeben und es kommt immer das richtige zurück.

Ja und genau diese "Genialität" an der Sache hat mich verwirrt :thumb:

oki 22. Sep 2004 15:08

Re: [Records] Codeoptimierung bei Übergabetypen
 
ja klar, denk an mein Bsp. mit den Autos. Wenn du es erweiterst und dann noch sagst das Auto ist vom Typ "englisch" (Lenker rechts), dann verstehst du auch das Thema mit den Typen. Gleiche Typen sind halt von Ihrem Aufbau identisch, ob nun String oder ein von dir erstellte spezieller Record den du type'st. Aufbau, Bezeichner, alles identisch. Nur was dann an Werten drin steht ist auf die entsprechende Variable dieses Typs bezogen.

Bei den Objekten, Klassen und ihren Instancen ist es genau so.

Gruß oki

scp 22. Sep 2004 15:19

Re: [Records] Codeoptimierung bei Übergabetypen
 
Gutes Beispiel. Dazu könnte man dann sagen, das der VTV dir nur den "Parkplatz" für die Autos zur Verfügung stellt. Der VTV muss nicht den Typ kennen und auch nicht wer drin sitzt (Inhalt), sondern nur die Grösse. Er gibt dir denn mit GetNodedata() den Stellpatz (Pointer) zurück.

maximov 22. Sep 2004 21:00

Re: [Records] Codeoptimierung bei Übergabetypen
 
Auch wenn das jetzt destruktiv ist:

Ich würde uneingeschränkt empfehlen solche geschichten mit klassen zu lösen. Da fällt dieser ganze record wahnsinn schonmal weg und man erspart sich massig probleme und gewinnt an dynamität. Erst recht wenn man bedenkt, das objekt 'nur' bessere records mit einem pointer auf die VMT sind :stupid: OOP rulez.

Ausnahmen bestätigen natürlich auch hier die regel, da es vor kommen kann, dass man alte daten in binär kompatiblen strukturen laden muss. Das sieht mir hier aber nicht so aus, denn sonst könntest du nicht mit dynamischen strings arbeiten.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:39 Uhr.
Seite 2 von 3     12 3      

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