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 VirtualStringTree und OnLoadNode (https://www.delphipraxis.net/47980-virtualstringtree-und-onloadnode.html)

GuenterS 18. Jun 2005 22:44


VirtualStringTree und OnLoadNode
 
Hallo,

jetzt kämpf ich schon eine ganze Weile mit dem VirtualStringTree. Ich möchte den Tree mit den dazu zur Verfügung gestellten Methoden "SaveToFile" und "LoadFromFile" speichern.

Jede Node enthält jedoch auch noch einen Record mit Daten, welche in den Ereignissen "OnSaveNode" und "OnLoadNode" in einen übergebenen Stream geschrieben bzw. von diesem gelesen werden müssen.

Wie es aussieht, klappt das Schreiben der Nodes.

Ich verwende folgenden Record, der mir die Daten hält welche ich im Node speichern möchte.
Delphi-Quellcode:
  PTreeData = ^TTreeData;
  TTreeData = record
    FileName: string;
    EntryType: TEntryType;
    Entry: TEntry;
  end;
TEntry ist die Basisklasse, verschiedener TEntryClassen, so gibt es CategoryEntry Klassen wie auch NoticeEntry Klassen.

Über EntryType kann unterschieden werden ob es sich um eine CategoryEntry Klasse oder eine NoticeEntry Klasse handelt.

Die TEntry Klasse:
Delphi-Quellcode:
  TEntryType = (etCATEGORY, etNOTICE);

  TEntry = class(TObject)
  private
    FCaption: string;
    FEntryType: TEntryType;
    FEntryFolder: string;
    FEntryFilename: string;
    function getEntryFullFileName: string;
    function getDataSize: integer;
  public

    procedure SaveMeToFile(aSourceComponent: TComponent); virtual;
    procedure LoadMeFromFile(aTargetComponent: TComponent; const aFilename: string); virtual;

    property EntryType: TEntryType read FEntryType write FEntryType;
    property Caption: string read FCaption write FCaption;
    property EntryFolder: string read FEntryFolder write FEntryFolder;
    property EntryFilename: string read FEntryFilename write FEntryFilename;
    property EntryFullFileName: string read getEntryFullFileName;
    property DataSize: integer read getDataSize;
  end;
Das Feld Caption ist das Feld, welches zur Beschriftung der Node hergenommen wird.

Die Eventroutine beim Speichern der Node schaut so aus:
Delphi-Quellcode:
procedure TfDataBox.vstSaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  lTreeData: PTreeData;
  lIntegerData: integer;
begin
  lTreeData := PTreeData(Sender.GetNodeData(Node)^);
  lIntegerData := Ord(lTreeData.EntryType);
  Stream.WriteBuffer(lIntegerData, sizeOf(lIntegerData));
  lIntegerData := length(lTreeData.FileName);
  Stream.WriteBuffer(lIntegerData, sizeOf(lIntegerData));
  Stream.WriteBuffer(PChar(lTreeData.FileName)^, lIntegerData);
end;
Die Eventroutine zum Laden der Nodes schaut so aus:
Delphi-Quellcode:
procedure TfDataBox.vstLoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  lTreeData: PTreeData;
  lEntryType: TEntryType;
  lIntegerData: integer;
  lFileName: string;
begin
  lTreeData := PTreeData(Sender.GetNodeData(Node)^);
  Stream.Read(lTreeData^.EntryType, sizeOf(integer));
  Stream.Read(lIntegerData, sizeOf(lIntegerData));
  setLength(lTreeData^.FileName, lIntegerData);
  Stream.Read(lTreeData^.FileName, lIntegerData);
  case lEntryType of
    etCATEGORY:
      begin
        lTreeData^.Entry := TCategoryEntry.Create;
        lTreeData^.Entry.LoadMeFromFile(nil, lFileName);
      end;
    etNOTICE:
      begin
        lTreeData^.Entry := TNoticeEntry.Create;
        lTreeData^.Entry.LoadMeFromFile(FNoticeEditor, lFileName);
      end;
  end;
end;

Jedoch bekomme ich beim Laden des Trees nur Access Violations, welche daher kommen, dass die Daten welche an den Nodes angehängt sein sollten, anscheinend nicht angehängt sind. Ich denke aber, dass ich genau das ja mit dieser Routine erreichen sollte.

Die NodeDataSize ist vorher schon auf die Größe von PTreeData festgelegt.

Weiß vielleicht jemand was ich falsch mache? Wieso mein Code nicht so funktioniert, wie ich mir das vorstelle?

marabu 19. Jun 2005 07:23

Re: VirtualStringTree und OnLoadNode
 
Hallo,

Zitat:

Zitat von GuenterS
Wie es aussieht, klappt das Schreiben der Nodes.

Da bin ich nicht so sicher.

Zu vstSaveNode():

Delphi-Quellcode:
begin
  ...
  lTreeData := Sender.GetNodeData(Node);
  ...
  Stream.WriteBuffer(lTreeData.FileName[1], lIntegerData);
end;
Zu vstLoadNode():

Delphi-Quellcode:
  lTreeData: PTreeData;
  lEntryType: TEntryType;
  lIntegerData: integer;
  lFileName: string;
begin
  lTreeData := Sender.GetNodeData(Node);
  ...
  Stream.Read(lTreeData.FileName[1], lIntegerData);
  case lTreeData.EntryType of
  ...
Zitat:

Zitat von GuenterS
Die NodeDataSize ist vorher schon auf die Größe von PTreeData festgelegt.

Besser wäre SizeOf(TTreeData).


Freundliche Grüße vom marabu

GuenterS 19. Jun 2005 08:59

Re: VirtualStringTree und OnLoadNode
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hm, habe Deine Korrekturen eingebaut, nur ich bekomme nun immer noch Access violations.

Da scheint es immer noch einen/mehrere Fehler zu geben.

Vielleicht hilft es ein wenig, wenn ich die Unit die den VST verwendet anhänge

marabu 19. Jun 2005 11:01

Re: VirtualStringTree und OnLoadNode
 
Hallo Günter,

wo bekommst du denn deine AV?

Ich habe mir deine Unit zwar runter geladen, aber sie ist in meiner Umgebung leider nicht ladbar.

Dein Code enthält an vielen Stellen:
Delphi-Quellcode:
with PTreeData(Sender.GetNodeData(Node)^) do .. ;
Mein Vorschlag war:
Delphi-Quellcode:
var
  ptd: PTreeData;
begin
  ptd := Sender.GetNodeData(Node);
  with ptd do ... ;
Du kannst aber auch so vorgehen:
Delphi-Quellcode:
with PTreeData(Sender.GetNodeData(Node))^ do .. ;
Da ist schon ein Unterschied...

marabu

GuenterS 19. Jun 2005 13:22

Re: VirtualStringTree und OnLoadNode
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab das mal versucht umzusetzen wie du das geschrieben hast, geht dann teilweise, habe dann aber andere Probleme, wie dass bei Neuen Nodes dann kein Text angezeigt wird, bis ich diesen Editiere.

Ich hab jetzt mal ein kleines Projekt gemacht, ich häng das da mal an, da wird jetzt dann nur 'Node' hingeschrieben, anstatt 'Neuer Eintrag'.


Ich hoff das kann man jetzt aufmachen.

marabu 19. Jun 2005 21:52

Re: VirtualStringTree und OnLoadNode
 
Hallo Günter,

wenn du dem VST einen Knoten hinzufügst, dann darfst du deinen TreeData-Record nicht selbst auf dem Heap anlegen - das macht der VST für dich. Um einen Zeiger auf deine Struktur zu erhalten, rufst du nach dem InsertNode() oder AddChild() mit dem von diesen Methoden zurückgegebenen node pointer die Methode GetNodeData() auf. Mit dieser Vorgehensweise solltest du in der Lage sein den von dir geschilderten Fehler zu beheben.

marabu

GuenterS 20. Jun 2005 07:10

Re: VirtualStringTree und OnLoadNode
 
Danke für den Hinweis, das werde ich heute abend ausprobieren.

Ich frage mich jetzt dann allerdings wofür der letzte Parameter der Methoden AddChild() bzw. InsertNode() dann dienen soll, wenn nicht zur Übergabe des PTreeData Records.

marabu 20. Jun 2005 08:06

Re: VirtualStringTree und OnLoadNode
 
Wenn deine Struktur TTreeData einen Pointer als erstes Feld definieren würde, dann könntest du durch die Übergabe von UserData (der zweite Parameter von AddChild) diesen Pointer für interne Steuerungszwecke initialisieren. Einfach weglassen, solange du das nicht brauchst.

marabu

GuenterS 20. Jun 2005 08:13

Re: VirtualStringTree und OnLoadNode
 
Soll ich das jetzt so verstehen, dass der Pointer den man bei AddChild() bzw. InsertNode() übergeben kann, nichts mit dem zu tun hat, den man sich über vst.GetNodeData(Node) holen kann?

Dann frage ich mich, allerdings wieso manche Teile funktioniert haben.

marabu 20. Jun 2005 09:04

Re: VirtualStringTree und OnLoadNode
 
Du hast mich richtig verstanden. Der "trotzdem funktionierende" Code war nicht in deinem Demo-Projekt, also kann ich dazu nichts sagen. Ist aber auch nicht so wichtig, hoffe ich.

marabu

GuenterS 20. Jun 2005 21:05

Re: VirtualStringTree und OnLoadNode
 
Liste der Anhänge anzeigen (Anzahl: 1)
So bin gerade nach Hause gekommen und habe versucht Deine Änderungsvorschläge einzubauen, jedoch funktioniert das mit dem kleinen Beispielprojekt überhaupt nicht. Es wird nach wie vor nur 'Node' angezeigt.

Ich habs mal wieder angehängt.

Igotcha 21. Jun 2005 00:12

Re: VirtualStringTree und OnLoadNode
 
Zitat:

Zitat von GuenterS
So bin gerade nach Hause gekommen und habe versucht Deine Änderungsvorschläge einzubauen, jedoch funktioniert das mit dem kleinen Beispielprojekt überhaupt nicht. Es wird nach wie vor nur 'Node' angezeigt.

Err, "Node" ist der Defaulttext für Nodeeinträge ;-)

Mittels "OnGetText" musst Du den Text setzen. In dem Event steuerst Du, welche Information in welcher "Column" angezeigt werden soll.

Beispiel:

Delphi-Quellcode:
procedure TKOM.VTISTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  myData: PIstData;
begin
    myData:=VTIST.GetNodeData(Node);
    Node.Align:=3;
  if (TextType=ttNormal) AND (myData.FGTyp<>6) then
  begin
    case Column of
    0: Celltext:=myData.FGBez;
    1: Celltext:=format('%.0n', [myData.FMonat[0]]);
    2: Celltext:=format('%.0n', [myData.FMonat[1]]);
    3: Celltext:=format('%.0n', [myData.FMonat[2]]);
    4: Celltext:=format('%.0n', [myData.FMonat[3]]);
    5: Celltext:=format('%.0n', [myData.FMonat[4]]);
    6: Celltext:=format('%.0n', [myData.FMonat[5]]);
    7: Celltext:=format('%.0n', [myData.FMonat[6]]);
    8: Celltext:=format('%.0n', [myData.FMonat[7]]);
    9: Celltext:=format('%.0n', [myData.FMonat[8]]);
    10: Celltext:=format('%.0n', [myData.FMonat[9]]);
    11: Celltext:=format('%.0n', [myData.FMonat[10]]);
    12: Celltext:=format('%.0n', [myData.FMonat[11]]);
    13: Celltext:=format('%.0n', [myData.FMonat[12]]);
    14: Celltext:=format('%.0n', [myData.FMonat[13]]);
    15: Celltext:=format('%.0n', [myData.FMonat[14]]);
    16: Celltext:=format('%.0n', [myData.FMonat[15]]);
    17: Celltext:=format('%.0n', [myData.FMonat[16]]);
    18: Celltext:=format('%.0n', [myData.FMonat[17]]);
    end;
  end;
Gruß Igotcha

GuenterS 21. Jun 2005 07:39

Re: VirtualStringTree und OnLoadNode
 
Zitat:

Zitat von Igotcha
Zitat:

Zitat von GuenterS
So bin gerade nach Hause gekommen und habe versucht Deine Änderungsvorschläge einzubauen, jedoch funktioniert das mit dem kleinen Beispielprojekt überhaupt nicht. Es wird nach wie vor nur 'Node' angezeigt.

Err, "Node" ist der Defaulttext für Nodeeinträge ;-)

Mittels "OnGetText" musst Du den Text setzen. In dem Event steuerst Du, welche Information in welcher "Column" angezeigt werden soll.

Beispiel:

Delphi-Quellcode:
procedure TKOM.VTISTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  myData: PIstData;
begin
    myData:=VTIST.GetNodeData(Node);
    Node.Align:=3;
  if (TextType=ttNormal) AND (myData.FGTyp<>6) then
  begin
    case Column of
    0: Celltext:=myData.FGBez;
    1: Celltext:=format('%.0n', [myData.FMonat[0]]);
    2: Celltext:=format('%.0n', [myData.FMonat[1]]);
    3: Celltext:=format('%.0n', [myData.FMonat[2]]);
    4: Celltext:=format('%.0n', [myData.FMonat[3]]);
    5: Celltext:=format('%.0n', [myData.FMonat[4]]);
    6: Celltext:=format('%.0n', [myData.FMonat[5]]);
    7: Celltext:=format('%.0n', [myData.FMonat[6]]);
    8: Celltext:=format('%.0n', [myData.FMonat[7]]);
    9: Celltext:=format('%.0n', [myData.FMonat[8]]);
    10: Celltext:=format('%.0n', [myData.FMonat[9]]);
    11: Celltext:=format('%.0n', [myData.FMonat[10]]);
    12: Celltext:=format('%.0n', [myData.FMonat[11]]);
    13: Celltext:=format('%.0n', [myData.FMonat[12]]);
    14: Celltext:=format('%.0n', [myData.FMonat[13]]);
    15: Celltext:=format('%.0n', [myData.FMonat[14]]);
    16: Celltext:=format('%.0n', [myData.FMonat[15]]);
    17: Celltext:=format('%.0n', [myData.FMonat[16]]);
    18: Celltext:=format('%.0n', [myData.FMonat[17]]);
    end;
  end;
Gruß Igotcha

Danke für Deinen Beitrag ;)
Wenn Du das angehängte Zip File angeschaut hättest, hättest Du sicher auch bemerkt, dass dies _nicht_ die Lösung für mein Problem ist, bzw. das Problem an anderer Stelle zu suchen ist.

marabu 21. Jun 2005 07:55

Re: VirtualStringTree und OnLoadNode
 
Hallo Günter,

in deinem Demo-Projekt fragst du im Ereignis OnGetText() auf Column = 0 ab. Das funktioniert nur, wenn du auch in vst.header.columns Spalten eingetragen hast. Ansonsten ist der Parameter Column von OnGetTExt() immer -1 und kann ignoriert werden.

marabu

GuenterS 21. Jun 2005 08:06

Re: VirtualStringTree und OnLoadNode
 
Ups, danke für den Hinweis, hab ich jetzt ganz übersehen. Im nicht Demo Projekt habe ich eine Column definiert, da hat die Abfrage auf column=0 funktioniert.

Bin gespannt obs funktioniert heute abend :), scheint aber eine sehr plausible Erklärung dafür zu sein, warum es vorher nicht geklappt hat.

:)

dahead 21. Jun 2005 08:57

Re: VirtualStringTree und OnLoadNode
 
wie wärs mit:

Code:
procedure TKOM.VTISTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  myData: PIstData;
begin
  myData := VTIST.GetNodeData(Node);
  Node.Align := 3;
  if (TextType = ttNormal) and (myData.FGTyp <> 6) then
  begin
   if Column = 0 then
    Celltext := myData.FGBez
   else
    Celltext := format('%.0n', [myData.FMonat[Column-1]]);
  end;

GuenterS 21. Jun 2005 09:06

Re: VirtualStringTree und OnLoadNode
 
Zitat:

Zitat von dahead
wie wärs mit:

Code:
procedure TKOM.VTISTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  myData: PIstData;
begin
  myData := VTIST.GetNodeData(Node);
  Node.Align := 3;
  if (TextType = ttNormal) and (myData.FGTyp <> 6) then
  begin
   if Column = 0 then
    Celltext := myData.FGBez
   else
    Celltext := format('%.0n', [myData.FMonat[Column-1]]);
  end;

oder
Code:
procedure TKOM.VTISTGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  myData: PIstData;
begin
  myData := VTIST.GetNodeData(Node);
  Node.Align := 3;
  if (TextType = ttNormal) and (myData.FGTyp <> 6) then
  begin
    case column of
      0: Celltext := myData.FGBez;
    else
      Celltext := format('%.0n', [myData.FMonat[Column-1]]);
    end;
  end;
end;

GuenterS 21. Jun 2005 19:45

Re: VirtualStringTree und OnLoadNode
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von marabu
Hallo Günter,

in deinem Demo-Projekt fragst du im Ereignis OnGetText() auf Column = 0 ab. Das funktioniert nur, wenn du auch in vst.header.columns Spalten eingetragen hast. Ansonsten ist der Parameter Column von OnGetTExt() immer -1 und kann ignoriert werden.

marabu

So danke, jetzt kommt zumindest keine Zugriffsverletzung mehr :) Speicher und Laden klappt auch, nun habe ich allerdings ein neues seltsames Verhalten des Trees beobachten können.

Zeitweise kann ich meine Nodes nicht auswählen mit der Maus und mit Tastatatur zeichnet er sich irgendwie sehr komisch.

Ich hab mal das ganze Projekt angehängt.

marabu 21. Jun 2005 20:38

Re: VirtualStringTree und OnLoadNode
 
Hallo Günter,

im Ereignis OnEdited() des VST solltest du folgende Zeile einfügen:

Delphi-Quellcode:
Sender.InvalidateNode(Node);
Sag mal, was ich machen muss um das unerwünschte Verhalten zu beobachten.

marabu

GuenterS 21. Jun 2005 20:41

Re: VirtualStringTree und OnLoadNode
 
An und für sich habe ich nur ein paar Kategorien und Notizen hinzugefügt und konnte mit der Maus nicht alle auswählen. Mit der Tastatur hab ich dann allerdings die Darstellung des Baumes ruiniert. Die Notizen sind zu Kategorien worden und umgekehrt.

Nachdem ich aber mal die Datei in welche ich das Speicher gelöscht habe, konnte ich es auch nicht mehr reproduzieren, vielleicht hatte ich in dieser Datei noch einen Knopf.


Ich danke Dir schon mal für Deine vielen Mühen, mit meinen Problemen. :thumb:

marabu 21. Jun 2005 20:53

Re: VirtualStringTree und OnLoadNode
 
OnEdited() ist nur wegen der Kosmetik - dadurch werden die geänderten Knotenbezeichner gleich auf die richtige Anzeigeweite gebracht. Kein Einfluß auf das sonstige Programmverhalten.

Den Rest überprüfe ich morgen früh.

marabu


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