Delphi-PRAXiS
Seite 1 von 2  1 2      

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/)
-   -   TVirtualStringTree mit TObjectList (https://www.delphipraxis.net/199906-tvirtualstringtree-mit-tobjectlist.html)

lowmax_5 28. Feb 2019 22:57

TVirtualStringTree mit TObjectList
 
Hallo,

ich stehe grad etwas auf dem Schlauch:
Ich möchte in einem TVirtualStringTree eine TObjectList anzeigen lassen die in etwa so aussieht:

Zeitraum Spalte1 Spalte2 Spalte 3
01/2019
==> Zeile1 Wert1 Wert2 Wert3
==> Zeile2 Wert3 Wert4 Wert5

02/2019
==> Zeile1 Wert6 Wert7 Wert8
==> Zeile9 Wert10 Wert11 Wert12


Als Ergebnis kommt aber nur folgendes raus:

Zeitraum Spalte1 Spalte2 Spalte 3
01/2019
==> Zeile1 Wert1 Wert2 Wert3
==> Zeile2 Wert3 Wert4 Wert5

02/2019
==> Node Node Node Node
==> Node Node Node Node

Was läuft das falsch? Wird das Object korrekt an ..GetText übergeben?


Die Objectlist ist wie folgt definiert:

Code:
unit uMyTypes;

interface

uses System.Classes,System.Generics.Collections;

type

  TDetailClass = class
   private
    FWert1: String;
    FCaption: String;
    FWert2: String;
    FWert3: String;
    procedure SetCaption(const Value: String);
    procedure SetWert1(const Value: String);
    procedure SetWert2(const Value: String);
    procedure SetWert3(const Value: String);
   public
    property Caption: String read FCaption write SetCaption;
    property Wert1: String read FWert1 write SetWert1;
    property Wert2: String read FWert2 write SetWert2;
    property Wert3: String read FWert3 write SetWert3;
  end;

  TDataClass = class
    private
    FZeitraum: String;
    FDetail1: TDetailClass;
    FDetail2: TDetailClass;
    procedure SetZeitraum(const Value: String);
    procedure SetDetail1(const Value: TDetailClass);
    procedure SetDetail2(const Value: TDetailClass);
    public
    constructor Create;
    destructor destroy;
    property Zeitraum: String read FZeitraum write SetZeitraum;
    property Detail1: TDetailClass read FDetail1 write SetDetail1;
    property Detail2: TDetailClass read FDetail2 write SetDetail2;
  end;

  PDataClass = ^TDataClass;

  TDataLst = TObjectList<TDataClass>;

implementation

{ TDetail }

procedure TDetailClass.SetCaption(const Value: String);
begin
  FCaption := Value;
end;

procedure TDetailClass.SetWert1(const Value: String);
begin
  FWert1 := Value;
end;

procedure TDetailClass.SetWert2(const Value: String);
begin
  FWert2 := Value;
end;

procedure TDetailClass.SetWert3(const Value: String);
begin
  FWert3 := Value;
end;

{ TData }



constructor TDataClass.Create;
begin
    FDetail1 := TDetailClass.Create;
    FDetail2 := TDetailClass.Create;
end;

destructor TDataClass.destroy;
begin
  FDetail1.Free;
  FDetail2.Free;
end;

procedure TDataClass.SetDetail1(const Value: TDetailClass);
begin
  FDetail1 := Value;
end;

procedure TDataClass.SetDetail2(const Value: TDetailClass);
begin
  FDetail2 := Value;
end;

procedure TDataClass.SetZeitraum(const Value: String);
begin
  FZeitraum := value;
end;


end.








Code:
procedure TForm5.Button10Click(Sender: TObject);
var
  vtc: TVirtualTreeColumn;
  vnHead: PVirtualNode;
  I: Integer;
  Data: TDataClass;
begin
  vstSP.Header.Options := vstSP.Header.Options + [hoVisible];


  vtc:= vstSP.Header.Columns.Add;
  vtc.Text:= 'Zeitraum';
  vtc.Width := 150;

  vtc:= vstSP.Header.Columns.Add;
  vtc.Text:= 'Wert1';
  vtc.Width := 100;

  vtc:= vstSP.Header.Columns.Add;
  vtc.Text:= 'Wert2';
  vtc.Width := 100;

  vtc:= vstSP.Header.Columns.Add;
  vtc.Text:= 'Wert3';
  vtc.Width := 100;


  vstSP.NodeDataSize:=SizeOf(TDataClass);

  vstSP.BeginUpdate;

  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Zeitraum := '01/2019';
  vnHead:= AddVSTStructureHeadClass(vstSP, nil, TDataClass(DataLst[0]));

  Data.Detail1.Caption:='Zeile1:';
  Data.Detail1.Wert1 := 'Det1 - Wert1';
  Data.Detail1.Wert2 := 'Det1 - Wert2';
  Data.Detail1.Wert3 := 'Det1 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, TDataClass(DataLst[0]));

  Data.Detail2.Caption:='Zeile2:';
  Data.Detail2.Wert1 := 'Det2 - Wert1';
  Data.Detail2.Wert2 := 'Det2 - Wert2';
  Data.Detail2.Wert3 := 'Det2 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, TDataClass(DataLst[0]));



  //Daten Fuellen2
  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Zeitraum := '02/2019';
  vnHead:= AddVSTStructureHeadClass(vstSP, nil, TDataClass(DataLst[1]));


  Data.Detail1.Caption:='Zeile1:';
  Data.Detail1.Wert1 := 'Det3 - Wert1';
  Data.Detail1.Wert2 := 'Det3 - Wert2';
  Data.Detail1.Wert3 := 'Det3 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, TDataClass(DataLst[1]));

  Data.Detail2.Caption:='Zeile2:';
  Data.Detail2.Wert1 := 'Det4 - Wert1';
  Data.Detail2.Wert2 := 'Det4 - Wert2';
  Data.Detail2.Wert3 := 'Det4 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, TDataClass(DataLst[1]));

  vstSP.EndUpdate;

  vstSP.FullExpand;

end;



procedure TForm5.vstSPFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  Data: PDataClass;
begin
  Data := vstSP.GetNodeData(Node);
  if Assigned(Data) then
  begin
    Data := nil;
  end;
end;


procedure TForm5.vstSPGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  Data: PDataClass;

begin
  Data := vstSP.GetNodeData(Node);


  if vstSP.GetNodeLevel(Node)=0 then
  //if Node.Index=0 then
  begin
    case Column of
      0: CellText := Data.Zeitraum;
      1: CellText := '';
      2: CellText := '';
      3: CellText := '';
    end;
  end;

 if vstSP.GetNodeLevel(Node)=1 then
 //if Node.Index=1 then
  begin
    if vstSP.AbsoluteIndex(Node)=1 then
    begin
      case Column of
        0: CellText := Data.Detail1.Caption;
        1: CellText := Data.Detail1.Wert1;
        2: CellText := Data.Detail1.Wert2;
        3: CellText := Data.Detail1.Wert3;
      end;
    end;

    if vstSP.AbsoluteIndex(Node)=2 then
  //  if Node.Index=2 then
    begin
      case Column of
        0: CellText := Data.Detail2.Caption;
        1: CellText := Data.Detail2.Wert1;
        2: CellText := Data.Detail2.Wert2;
        3: CellText := Data.Detail2.Wert3;
      end;
    end;

  end;



end;

bcvs 1. Mär 2019 07:24

AW: TVirtualStringTree mit TObjectList
 
Jeder Node des Vst sollte sein eigenes Data-Objekt haben.

Dann kannst du auch auf die Unterscheidung Detail1 und Detail2 verzeichten und hast einfach nur noch Detail.

Im GetText kannst du dann bei NodeLevel = 1 einfach die Werte des Data-Objekts des jeweiligen Nodes ausgeben und musst nicht auf AbsoluteIndex prüfen. Das funktioniert hier nämlich nicht so, wie du dir das vorgestellt hast. Die beiden letzten Detailzeiten wären AbsoluteIndex 4 und 5.

lowmax_5 1. Mär 2019 08:50

AW: TVirtualStringTree mit TObjectList
 
Vielen Dank für die Hilfe!

Zitat:

Im GetText kannst du dann bei NodeLevel = 1 einfach die Werte des Data-Objekts des jeweiligen Nodes ausgeben und musst nicht auf AbsoluteIndex prüfen. Das funktioniert hier nämlich nicht so, wie du dir das vorgestellt hast. Die beiden letzten Detailzeiten wären AbsoluteIndex 4 und 5.
Hier hatte ich einen Gedankenfehler. Ist nun natürlich logisch...


Aktuell hakt es nur beim zweiten Child. Wie bekomme ich da unterschiedliche Daten im zweiten Child angezeigt?
Ich hatte bereits auf ein Detail zurückgebaut und AbsoluteIndex entfernt...

ConnorMcLeod 1. Mär 2019 09:03

AW: TVirtualStringTree mit TObjectList
 
Vllt hakt es noch am Verständnis, wie GetText aufgerufen wird? Nämlich für jeden Node extra. Es ist nicht notwendig, alle Nodes in der Funktion abzuarbeiten...

lowmax_5 1. Mär 2019 09:29

AW: TVirtualStringTree mit TObjectList
 
Aktuell fülle ich die Struktur mit:


Code:
  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Zeitraum := '01/2019';
  vnHead:= AddVSTStructureHeadClass(vstSP, nil, TDataClass(DataLst[0]));

  Data.Detail.Caption:='Zeile1:';
  Data.Detail.Wert1 := 'Det1 - Wert1';
  Data.Detail.Wert2 := 'Det1 - Wert2';
  Data.Detail.Wert3 := 'Det1 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, DataLst[0].Detail);

  Data.Detail.Caption:='Zeile2:';
  Data.Detail.Wert1 := 'Det2 - Wert1';
  Data.Detail.Wert2 := 'Det2 - Wert2';
  Data.Detail.Wert3 := 'Det2 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, DataLst[0].Detail);

GetText:

Code:
procedure TForm5.vstSPGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
  Data: PDataClass;
  Detail : PDetailClass;

begin
      Detail := vstSP.GetNodeData(Node);

  if vstSP.GetNodeLevel(Node)=0 then
  begin
    Data := vstSP.GetNodeData(Node);
     Data := vstSP.GetNodeData(Node);
    case Column of
      0: begin
           CellText := Data.Zeitraum;
         end;
      1: CellText := '';
      2: CellText := '';
      3: CellText := '';
    end;
  end;

 if vstSP.GetNodeLevel(Node)=1 then
 begin
      case Column of
        0: CellText := Detail.Caption;
        1: CellText := Detail.Wert1;
        2: CellText := Detail.Wert2;
        3: CellText := Detail.Wert3;
      end;

    end;
end;


Im Ergebnis wird für beide Childs nur Zeile 2 angezeigt :roll:

bcvs 1. Mär 2019 09:42

AW: TVirtualStringTree mit TObjectList
 
Du musst für jeden Node eine eigene Instanz von TDataClass erzeugen und die auch in der DataLst speichern:
Delphi-Quellcode:
  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Zeitraum := '01/2019';
  vnHead:= AddVSTStructureHeadClass(vstSP, nil, Data);

  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Detail.Caption:='Zeile1:';
  Data.Detail.Wert1 := 'Det1 - Wert1';
  Data.Detail.Wert2 := 'Det1 - Wert2';
  Data.Detail.Wert3 := 'Det1 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, Data.Detail);

  Data := TDataClass.Create;
  DataLst.Add(Data);
  Data.Detail.Caption:='Zeile2:';
  Data.Detail.Wert1 := 'Det2 - Wert1';
  Data.Detail.Wert2 := 'Det2 - Wert2';
  Data.Detail.Wert3 := 'Det2 - Wert3';
  AddVSTStructureDetailClass(vstSP, vnHead, Data.Detail);

lowmax_5 1. Mär 2019 09:53

AW: TVirtualStringTree mit TObjectList
 
Argh :stupid:, dass war es!
Kann im Nachgang auch nicht anders funktionieren...

Vielen Dank!!!

bcvs 1. Mär 2019 09:59

AW: TVirtualStringTree mit TObjectList
 
Was mir noch aufgefallen ist: Das FreeNode des vst brauchst du nicht. Deine Data-Objekte werden ja von der DataLst verwaltet und freigegeben. Da ist es nicht gut, wenn der vst diese Objekte auf nil setzt.

Aviator 1. Mär 2019 11:11

AW: TVirtualStringTree mit TObjectList
 
Zitat:

Zitat von bcvs (Beitrag 1426694)
Was mir noch aufgefallen ist: Das FreeNode des vst brauchst du nicht. Deine Data-Objekte werden ja von der DataLst verwaltet und freigegeben. Da ist es nicht gut, wenn der vst diese Objekte auf nil setzt.

Auf
Delphi-Quellcode:
nil
setzen ist nicht schlimm. Er gibt es ja nicht frei. Schlimmer wäre es, wenn er es bereits freigeben würde. Dann gäbe es eine AV.

Anders wäre das wenn er Interfaces nutzen würde. Dann muss er sie auch dort auf nil setzen, da sonst der Referenzzähler nicht dekrementiert wird.

bcvs 1. Mär 2019 11:19

AW: TVirtualStringTree mit TObjectList
 
Zitat:

Zitat von Aviator (Beitrag 1426712)
Auf
Delphi-Quellcode:
nil
setzen ist nicht schlimm. Er gibt es ja nicht frei. Schlimmer wäre es, wenn er es bereits freigeben würde. Dann gäbe es eine AV.

Und was ist, wenn die TOjectList später ihre Items freigeben will? Dann sind die nil und es gibt Speicherlecks.

Außerdem könnte es ja sein, dass man die Items außerhalb des VST noch braucht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:05 Uhr.
Seite 1 von 2  1 2      

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