![]() |
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:
Und zweitens ist ein Record nicht zu einem Pointer kompatibel, wie du es geschrieben hast:
adata[b].FGBez[/b] := ...;
Code:
Das hingegen würde gehen:
adata := MyPointer;
Delphi-Quellcode:
Also überdenk noch mal, was du eigentlich machen willst.
type
TData = record ...; end; PData = ^TDate; var adata: PData; ... adata := PData(MyPointer); |
Re: [Records] Codeoptimierung bei Übergabetypen
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Müsste in allen drei Fällen auf die gleichen Inhalte zeigen, wenn ich das richtig sehe. Und bei
type
TData = record ...; end; PData = ^TDate; var Istdaten: PData; Plandaten: PData; Prognosedaten: PData;
Delphi-Quellcode:
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:
type
TData = record ...; end; PData1 = ^TDate; PData2 = ^TDate; PData3 = ^TDate; var Istdaten: PData1; Plandaten: PData2; Prognosedaten: PData3;
Delphi-Quellcode:
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.
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 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:
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.
procedure BildeSumme(TreeViewIstDaten, IstDatenrecord)
procedure BildeSumme(TreeViewPlanDaten, PlanDatenrecord) procedure BildeSumme(TreeViewPrognoseDaten, PrognoseDatenrecord) Um mal bei meiner Ursprungsdeklaration zu bleiben, folgendes (unsinniges) Beispiel ist möglich:
Delphi-Quellcode:
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.
var
myIst: pIstdaten; myPlan: pPlandaten; begin myIst:=TreeviewIst.GetNodeData(Node); myPlan:=TreeviewIst.GetnodeData(Node); 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:
Gruß Igotcha
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; |
Re: [Records] Codeoptimierung bei Übergabetypen
Also nach wie vor sollte dies die richtige Lösung sein:
Delphi-Quellcode:
Was meinst du denn mit
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; Zitat:
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; |
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:
Hier wird mir schon etwas mulmig. Warum greift er auf den richtigen Record-Typ zu?
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;
Delphi-Quellcode:
Und hier wird mir ganz schwummerig ;-) Ich habe beiden Treeviews (TIST, TPLAN) die gleiche Ereignis-Routine zugewiesen (dient zur Anzeige der Inhalte):
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;
Delphi-Quellcode:
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.
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; Vielen Dank und Gruß Igotcha ... der jetzt wohl einige Tage seinen Code dahingehend anpassen wird... |
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.
|
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 |
Re: [Records] Codeoptimierung bei Übergabetypen
Zitat:
|
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 |
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.
|
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 19:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz