Delphi-PRAXiS

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)

Igotcha 21. Sep 2004 15:33


[Records] Codeoptimierung bei Übergabetypen
 
Hallo zusammen,

nachdem ich in meiner Anwendung so gut wie alle Basisfunktionalitäten implementiert habe, möchte ich mich an die Codeoptimierung machen. Speziell stelle ich mir hier Fragen zum Thema Records, da diese zur Laufzeit in Verbindung mit vier VirtualTreeviews zur Datenhaltung benutzt werden.

Ich stelle in 3 der 4 VTVs verschiedene Daten mit der gleichen Record-Struktur dar:

Delphi-Quellcode:
type
  PPrognoseData = ^TPrognoseData;
  TPrognoseData = record
    FGid: integer;
    FPid: integer;
    FGroupid: integer;
    FGBez: String;
    FGTyp: integer;
    FGColor: String;
    FGS1: String;
    FGOP1: String;
    FGS2: String;
    FGOP2: String;
    FGS3: String;
    FMonat: Array [0..16] of double;
end;

type
  PIstData = ^TIstData;
  TIstData = record
    FGid: integer;
    FPid: integer;
    FGroupid: integer;
    FGBez: String;
    FGTyp: integer;
    FGColor: String;
    FGS1: String;
    FGOP1: String;
    FGS2: String;
    FGOP2: String;
    FGS3: String;
    FMonat: Array [0..16] of double;
end;

type
  PPlanData = ^TPlanData;
  TPlanData = record
    FGid: integer;
    FPid: integer;
    FGroupid: integer;
    FGBez: String;
    FGTyp: integer;
    FGColor: String;
    FGS1: String;
    FGOP1: String;
    FGS2: String;
    FGOP2: String;
    FGS3: String;
    FMonat: Array [0..16] of double;
end;
Das "Optimierungsproblem" besteht jetzt darin, dass, wenn ich auf die Daten innerhalb der einzelnen VTVs zugreifen möchte (lesen, editieren), die Daten so zugewiesen werden müssen (hier für die IstDaten):

Delphi-Quellcode:
procedure ...
var
  myData : pIstData;
  mydouble: double;
begin
   myData:=TIST.GetNodeData(Node); // Die Funktion GetNodeData gibt einen Verweis auf den Recordeintrag zurück, der für den Node "Node" hinterlegt ist. An dieser Stelle existiert also eine Verknüpfung vom VTV zu den IstDaten
   myData.FGBez:='etc.'; oder
   mydouble:=myData.FMonat[0];
TIST ist der VTV, der die IstDaten "verwaltet", den ich per Parameter übergeben kann.

Dies hat im Moment zur Folge, dass ich für alle Routinen, die etwas mit den drei VTVs anstellen, eine eigene Version habe - nämlich abhängig vom Record-Typ :-(

Da die Record-Struktur in allen drei Fällen gleich ist, suche ich nun nach einer Optimierungsmöglicheit in der Form, dass ich beim Aufruf der Routinen "irgendwie" den Record-Typ mit übergeben und dann innerhalb der Routine damit arbeiten kann.

Also etwas in der Art wie:

Delphi-Quellcode:
procedure DoSomething(atree: TVirtualStringTree; arecord: ???);
begin
    arecord:=atree.GetNodeData(Node);
    arecord.FGBez:='Test';
    ...
end;

So dass ich dann die Procedure so aufrufen könnte:

DoSomething(TIST, pIstData);
Gruß Igotcha

Igotcha 22. Sep 2004 09:10

Re: [Records] Codeoptimierung bei Übergabetypen
 
Ich möchte meine Frage gerne nochmal nach oben pushen mit dem Hintergrund, ob ich mich evtl. in der Fragestellung ungenügend ausgedrückt habe. Die Frage ist mir nämlich sehr wichtig.

Gruß Igotcha

Luckie 22. Sep 2004 09:15

Re: [Records] Codeoptimierung bei Übergabetypen
 
Wenn alle Records identisch sind, warum hast du sie denn drei mal deklariert?

Delphi-Quellcode:
type
  TDaten = record
  ...;
  ...;
  ...;
end;


var
 IstDaten, SollDaten, MoechteDaten: TDaten;

Igotcha 22. Sep 2004 09:33

Re: [Records] Codeoptimierung bei Übergabetypen
 
Zitat:

Zitat von Luckie
Wenn alle Records identisch sind, warum hast du sie denn drei mal deklariert?

Delphi-Quellcode:
type
  TDaten = record
  ...;
  ...;
  ...;
end;


var
 IstDaten, SollDaten, MoechteDaten: TDaten;

So hätte ich mir das auch gedacht, nur, wie unterscheidet sich Deine Deklaration von dieser aus technischer Sicht? Die folgende Art der Deklaration ist so in sämtlichen Unterlagen zum VTV zu finden:

Delphi-Quellcode:
type
  PPrognoseData = ^TPrognoseData;
  TPrognoseData = record
Und funktioniert bei Deinem Record auch die o.g. Zugrifssmethode (die ja einen Zeiger auf meinen Record-Satz liefert)?

Gruß Igotcha

Sharky 22. Sep 2004 09:38

Re: [Records] Codeoptimierung bei Übergabetypen
 
Hai Igotcha,
es sollte eigentlich so machbar sein:
Delphi-Quellcode:
type
  PPrognoseData = ^TData;
  PIstData = ^TData;
  PPlanData = ^TData;

  TData = record
    FGid: integer;
    FPid: integer;
    FGroupid: integer;
    FGBez: String;
    FGTyp: integer;
    FGColor: String;
    FGS1: String;
    FGOP1: String;
    FGS2: String;
    FGOP2: String;
    FGS3: String;
    FMonat: Array [0..16] of double;
end;

Igotcha 22. Sep 2004 09:44

Re: [Records] Codeoptimierung bei Übergabetypen
 
Zitat:

Zitat von Sharky
Hai Igotcha,
es sollte eigentlich so machbar sein:
Delphi-Quellcode:
type
  PPrognoseData = ^TData;
  PIstData = ^TData;
  PPlanData = ^TData;

  TData = record
    FGid: integer;
    FPid: integer;
    FGroupid: integer;
    FGBez: String;
    FGTyp: integer;
    FGColor: String;
    FGS1: String;
    FGOP1: String;
    FGS2: String;
    FGOP2: String;
    FGS3: String;
    FMonat: Array [0..16] of double;
end;

Ok, das wäre eine Simplifizierung der Record-Deklaration - schon mal gut ;-)

Aber wie kann ich jetzt dafür den Übergabeparameter in Proceduren definieren?

Delphi-Quellcode:
procedure DoSomething(atree: TVirtualStringTree; arecord: TData)

oder

procedure DoSomething(atree: TVirtualStringTree; arecord: ^TData)
Sorry, dass ich viel Frage, ohne es evtl. im Code zu testen, aber meine Anwendung hat im Moment ca. 60.000 Zeilen Code und bei der testweisen Änderung z.B. der Recorddefinition würde ich einen Tag sitzen, nur um den Code anzupassen, um dann evtl. festzustellen, dass es nicht funktioniert ;-)

Gruß Igotcha

Luckie 22. Sep 2004 09:45

Re: [Records] Codeoptimierung bei Übergabetypen
 
@Igotcha: Ich habe nur die Zeiger-Deklaration auf den Record weggelassen.

ibp 22. Sep 2004 09:51

Re: [Records] Codeoptimierung bei Übergabetypen
 
imho so:

Code:
procedure DoSomething(atree: TVirtualStringTree; VAR arecord: ^TData)

Igotcha 22. Sep 2004 10:45

Re: [Records] Codeoptimierung bei Übergabetypen
 
Danke Euch!

Ich werde mal ein kleines Testprojekt aufsetzen und mich dann wieder melden...

Igotcha 22. Sep 2004 11:02

Re: [Records] Codeoptimierung bei Übergabetypen
 
Hmmm, leider geht es offensichtlich so nicht :-(

Delphi-Quellcode:
type
  PPrognoseData = ^TData;
  PIstData = ^TData;
  PPlanData = ^TData;

  TData = record
    FGBez: String;
    FMonat: Array [0..1] of double;
end;

...

 public
    { Public declarations }
    procedure BuildTree(atree: TVirtualStringTree; var adata: TData);
  end;

...

procedure TForm1.BuildTree(atree: TVirtualStringTree; var adata: TData);
var
 myNode : PVirtualNode;
begin
      aTree.Clear;
      aTree.NodeDataSize:=sizeof(adata);
      myNode:=atree.AddChild(nil);
      adata:=atree.GetNodeData(myNode); // hier kommt der Fehler
end;
Ergibt beim Compilieren:

[Error] Unit1.pas(55): Incompatible types: 'TData' and 'Pointer'

Die Variante

Delphi-Quellcode:
procedure BuildTree(atree: TVirtualStringTree; var adata: ^TData);
Ergibt ein:

[Error] Unit1.pas(35): Identifier expected but '^' found

Nicht gut ;-)

Gruß Igotcha

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.

oki 23. Sep 2004 08:06

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

mein erster Gedanke war auch der Hinweis auf ein Object. Persönlich überlege ich aber auch immer erst was ich noch für zusätzlichen Aufwand betreiben muß.
Üblicherweise verwende ich Records immer dann, wenn ich relativ viele Daten in Funktionen und Procedure übergeben muß. Ich finde es einfach nervig Methoden mit einem Rattenschwanz von Parametern zu verwenden. Bei Tree's ist man im Parameter Data nun mal an den Pointer gebunden (auch gut so). So lange es dann auch nur um das Halten von Daten geht, verwende ich recht gerne Records.
Müssen die daten aber "manipuliert", bearbeitet oder Ausgewertet werden, so schreibe ich mir lieber eine eigene Klasse. Das macht den eigentlichen Quellcode gerade bei mehrfachen Zugriffen kürzer und übersichtlicher. Der Schreibaufwand für diese Klassen ist dann aber erst mal größer(vorausgesetzt man macht es "ordentlich").

Bei diesem Beispiel wissen wir nun nicht genau wieviel Bearbeitungsaufwand folgt. Grundsätzlich lege ich auch Records bei Tree's an. Ich finde den Hinweis für die Verwendung einer Klasse aber intreressant. Zumindest müßte Igotcha in seiner Form-Unit nicht seperate Methoden für die Datenbearbeitung platzieren die mit dem Fenster in der Form nichts zu tun haben, sondern eigentlich datenbezogen agieren. Mir fällt es bei dieser Art der Programmierung selber immer wieder schwer nach längerer Zeit zu verstehen, was ich da geprogt habe.

Gruß oki

oki 23. Sep 2004 08:25

Re: [Records] Codeoptimierung bei Übergabetypen
 
hi,

ich hab mal einen Ansatz für so ein Object zusammen geschrieben.
Delphi-Quellcode:
type TMonatArr = Array [0..16] of double;

type
  TDaten = class(TObject)
  private
    FGroupid: integer;
    FGTyp: integer;
    FGrid: integer;
    FPid: integer;
    FGS3: String;
    FGColor: String;
    FGS2: String;
    FGOP1: String;
    FGOP2: String;
    FGS1: String;
    FGBez: String;
    FMonat: TMonatArr;
  protected
  public
    property Gid: integer read FGrid write FGrid;
    property Pid: integer read FPid write FPid;
    property Groupid: integer read FGroupid write FGroupid;
    property GBez: String read FGBez write FGBez;
    property GTyp: integer read FGTyp write FGTyp;
    property GColor: String read FGColor write FGColor;
    property GS1: String read FGS1 write FGS1;
    property GOP1: String read FGOP1 write FGOP1;
    property GS2: String read FGS2 write FGS2;
    property GOP2: String read FGOP2 write FGOP2;
    property GS3: String read FGS3 write FGS3;
    property Monat: TMonatArr read FMonat write FMonat;
end;
hier können jetzt alle Methoden eingearbeitet werden, die Aktionen für die zu haltenden Daten durchführen, ohne dass mann dafür von "Außen" sorgen muß.

Wie gesagt, nur um Daten zu halten ist mir der Aufwand zu groß. Geht es dann aber ein Stück weiter, machts dann mit classen wieder Spaß.

Gruß oki

Igotcha 23. Sep 2004 08:55

Re: [Records] Codeoptimierung bei Übergabetypen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,

ich finde es toll, dass Ihr Euch weiter um das Thema bemüht :thumb:

Deshalb ein paar Infos zu mir und dem Programm:

Ich bin kein studierter Informatiker, sondern studierter Kaufmann mit langjähriger Hobby-Programmiererfahrung und habe in meinem Beruf als Berater in einem Produkt-und Softwarehaus für einen Kunden eine ähnliche Lösung in Excel entwickeln müssen. Excel war Kundenwunsch. Das Ganze ist ein hierarchisches Prognosetool, welches Prognosewerte von z.B. Bereichsleiterebene auf Geschäftsbereichsebene bis hin zur Konzernebene aggregiert und später auswertet. Dazu werden dem Anwender seine Plandaten und die Istdaten in das System eingespielt und dieser hat z.B. wöchentlich eine Prognose über die künftige Entwicklung abzugeben. Zusätzlich wird noch eine Abweichungsübersicht erstellt, damit der Anwender alle Informationen parat hat, für die er verantwortlich ist, etc.

Dann sollte (die Betonung liegt auf sollte) ich für unseren Geschäftsbereich ein erweitertes System dieser Art aufsetzen (mit weniger Anwendern) woraufhin ich unseren Chef in Bezug auf Excel aus meiner Erfahrung damit vorgewarnt habe - hat nichts genützt. Natürlich hat sich gezeigt, dass Excel für so etwas mehr schlecht als recht geeignet ist (Thema Wartung) und irgendwann habe ich mir privat überlegt, das Ganze "richtig" zu programmieren. Mit zentraler Datenbank, etc. Momentan habe ich einen Stand erreicht, der funktioniert - sozusagen die 1.0 Version.

An Objekte habe ich natürlich auch gedacht, bin aber aus zwei Gründen erstmal davon abgekommen:

- der erste Grund war, dass ich überhaupt erstmal eine Komponente finden musste, die es mir ermöglich, die "Vision" des Programms visuell zu verwirklichen (das ist aus Anwendersicht ein sehr wichtiger Punkt). Da bin ich dann irgendwann beim VirtualTreeView gelandet,
- der zweite Grund war, mit dem Programm schnell so etwas wie eine Machbarkeitsstudie zu realisieren - also zu zeigen, dass es überhaupt so geht, denn ich möchte das Programm evtl auch vermarkten.

Zum Programm:

Jeder Anwender sieht in dem Programm vier Sichten auf seinen Bereich:

- Prognose, Ist, Plan und Abweichung, jeweils in Form eines VTVs
- jede Sicht besteht aus ~ 140 Zeilen (Erlöse, Kosten, statische Zeilen), wobei in 3 der 4 VTVs jede Zeile aus o.g. Recordstruktur besteht (die Abweichungssicht hat ein kleineres Record)
- jede Sicht wird dynamisch strukturiert aufgebaut (die Struktur ist konfigurierbar, kann also je nach Organisationsbedürfnissen angepasst werden)
- basierend auf dieser Struktur werden Gruppen-, Untergruppen-, Zeilen- und Quartalssummen automatisch generiert
- zusäzlich sind "statische" Zeilen möglich. Also Zeilen, die das mathematische Ergebnis aus bis zu drei anderen Zeilen darstellen. Beispiel: Ebit_1=Umsatz-Kosten
- grundsätzlich ist es möglich, jede Zeile als berechnetes Ergebnis von bis zu 3 anderen Zeilen darzustellen,
- Eingaben in der Prognosesicht führen dazu, dass natürlich die Prognosesicht aktualisiert werden muss und die geänderten Daten in die Datenbank geschrieben werden. Zusätzlich ändert sich aber auch dabei die Ist-Sicht, denn diese ist wie folgt aufgebaut: sofern Istdaten für den Monat vorhanden sind, zeige die Istdaten an, andernfalls die entsprechenden Prognosedaten. Wenn wir also z.B. die Istdaten bis August vorliegen haben, werden für JAN-AUG die Istdaten und für SEP-DEZ die Prognosedaten angezeigt, um das vorraussichtliche Jahresergebnis zu ermitteln
- dann gibt es Exportfunktionen nach TXT und Excel
- etc.

Objekte sind in einer zukünftigen Version sicher eine Alternative, aber da würde ich mich erst ransetzen, wenn ich genau weiss, was ich alles benötige. Bisher steht der kaufmännische Aspekt (also die inhaltliche Funktionalität) des Programms im Vordergrund.

Gruß Igotcha

EDIT: Hab mal einen Screenshot beigelegt.


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