Autor Beitrag
teamrocket0
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 1

Win ME, Win XP, Win 7, Win 10
Delphi 7, 10.2 Tokyo
BeitragVerfasst: Mo 16.09.24 14:29 
Hallo Delphi Community, teamrocket hier.

Ich bastle gerade ein Programm das eine Remote Desktop Manager werden soll, da ich mit dem auf dem Markt vorhanden Zeug irgendwie nicht zufrieden bin. :?
Als Übersicht versuche ich ein "VirtualStringTree" zu verwenden.

Das füttern mit Informationen der jeweiligen "Parent-Node" bzw. "Child-Node" funktioniert glaube ich schon ganz gut.
Auch das verwenden der "Meta-Daten" des jweiligen Node funktioniert erstmal. Glaube ich... :o

Das was ich derzeit nicht auf die Reihe bekomme ist, den gesamten "VirtualStringTree" samt "Meta-Daten" in einem "Stream" zu sichern.
Also, das speichern scheint zwar zu erfolgen und das Laden des Stream auch, jedoch erhalte ich nach dem Laden der "Stream-Datei" eine Fehlermeldung. :?:


Zugrifsverletzung bei Adresse "Blakeks" in Modul "Project1.exe"... :oops:

In der officellen Dokumentation finde ich folgende Zeile, mit der ich nichts anfangen kann.
ausblenden Delphi-Quelltext
1:
2:
3:
begin
  // save type of the node
  Stream.Write(Art, SizeOf(Art));


Ich habe mich an folgenden Beitrag aus dem "Stackoverflow" Forum gehalten :?!?:
ausblenden HTML-Dokument
1:
https://stackoverflow.com/questions/45606992/how-to-save-load-to-from-file-in-virtualtree-component-using-delphi					


Kennt sich jemand von euch mit dem speichern des "VirtualStringTree" aus?

Mein bisheriger Quellcode: :P

VirtualStringView Typ-Deklaration
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
type
  PMyRec = ^TMyRec;
  TMyRec = record
    Caption:        WideString; //Anzeigename im Tree
    ServerAdress:   String;     //Hostname bzw. IP-Adresse in Tabelle schreiben
    Username:       String;     //User-Name
    Domain:         String;     //Domainname
    ClearPW:        WideString; //Klartestpasswort
    wallpaper:      Integer;    //Hintergrundbild anzeigen (std. 0)
    reconnection:   Integer;    //automatisches neu verbinden (std. 1)
    clipboard:      Integer;    //Zwischenablage benutzen (std. 1)
    printers:       Integer;    //Drucker in Remotesitzung benutzen (std. 0)
    PointerNodeData:Pointer;
  end;


im FreeNode-Ereigniss
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.VirtualStringTree1FreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: PMyRec;
begin
  Data := Sender.GetNodeData(Node);
  // Explicitely free the string, the VCL cannot know that there is one but needs to free
  // it nonetheless. For more fields in such a record which must be freed use Finalize(Data^) instead touching
  // every member individually.
  Finalize(Data^);
end;


im GetNodeDatraSize-Ereigniss
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.VirtualStringTree1GetNodeDataSize(Sender: TBaseVirtualTree;
  var NodeDataSize: Integer);
begin
  NodeDataSize := SizeOf(TMyRec);//WITHOUT THE CODE,ERROR COMING .
end;


Das OnGetText-Ereigniss
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
var
  Data: PMyRec;
begin
  // A handler for the OnGetText event is always needed as it provides the tree with the string data to display.
  Data := Sender.GetNodeData(Node);
  if Assigned(Data) then
    CellText := Data.Caption;
end;


Das OnInitNode-Ereigniss
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.VirtualStringTree1InitNode(Sender: TBaseVirtualTree;
  ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
  Data: PMyRec;
begin
  with Sender do
  begin
    Data := GetNodeData(Node);
    // Construct a node caption. This event is triggered once for each node but
    // appears asynchronously, which means when the node is displayed not when it is added.
    //Data.Caption := Format('Test %d, Index %d', [GetNodeLevel(Node), Node.Index]);
    Data.Caption := Format(DisplayName, [GetNodeLevel(Node), Node.Index]);
  end;
end;


Für das OnLoadNode-Ereigniss
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure TForm1.VirtualStringTree1LoadNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PMyRec;
  Len: Integer;
begin
      Data := Form1.VirtualStringTree1.GetNodeData(Node);

      Stream.read(Len, SizeOf(Len));
      SetLength(Data^.Caption, Len);
      Stream.read(PChar(Data^.Caption)^, Len*SizeOf(Char));

      Stream.read(Len, SizeOf(Len));
      SetLength(Data^.ServerAdress, Len);
      Stream.read(PChar(Data^.ServerAdress)^, Len*SizeOf(Char));

      Stream.read(Len, SizeOf(Len));
      Stream.read(Data.wallpaper, SizeOf(Data.wallpaper));

      Stream.read(Len, SizeOf(Len));
      Stream.read(Data.reconnection, SizeOf(Data.reconnection));

      Stream.read(Len, SizeOf(Len));
      Stream.read(Data.clipboard, SizeOf(Data.clipboard));

      Stream.read(Len, SizeOf(Len));
      Stream.read(Data.printers, SizeOf(Data.printers));

      Stream.read(Len, SizeOf(Len));
      Stream.Read(Data.PointerNodeData, SizeOf(Data.PointerNodeData));
end;


Und zu guter Letzt das OnSaveNode-Ereigniss
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
procedure TForm1.VirtualStringTree1SaveNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Stream: TStream);
var
  Data: PMyRec;
  Len: Integer;
begin
  Data := Form1.VirtualStringTree1.GetNodeData(Node);

  Len := Length(Data^.Caption);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data^.Caption)^, Len*SizeOf(Char));

  Len := Length(Data^.ServerAdress);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data^.ServerAdress)^, Len*SizeOf(Char));

  Len := Length(Data^.Username);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data^.Username)^, Len*SizeOf(Char));

  Len := Length(Data^.Domain);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data^.Domain)^, Len*SizeOf(Char));

  Len := Length(Data.ClearPW);
  Stream.write(Len, SizeOf(Len));
  Stream.write(PChar(Data^.ClearPW)^, Len*SizeOf(Char));

  Stream.write(Data^.wallpaper, SizeOf(Data^.wallpaper));

  Stream.write(Data^.reconnection, SizeOf(Data^.reconnection));

  Stream.write(Data^.clipboard, SizeOf(Data^.clipboard));

  Stream.write(Data^.printers, SizeOf(Data^.printers));

  Stream.Write(Data^.PointerNodeData, SizeOf(Data^.PointerNodeData))
end;


Speicher-Button
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.Button4Click(Sender: TObject);
var
NodeSafe: TFileStream;
begin
Form1.VirtualStringTree1.SaveToFile(ExtractFilePath(ParamStr(0))+ 'Connections.at1');
end;


Laden Knopf
ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.Button5Click(Sender: TObject);
begin
Form1.VirtualStringTree1.LoadFromFile(ExtractFilePath(ParamStr(0))+ 'Connections.at1');
end;


Ich habe sicherlich nur eine Kleinigkeit übersehen oder alles komplett falsch gemacht. :shock:
Bitte schaut euch das einmal an. Vielleicht kann mir jemand sagen wo der Fehler liegt.

Ich danke für eure Zeit,

teamrocket0

_________________
To be forgotten is worse than death!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4777
Erhaltene Danke: 1054

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 17.09.24 18:26 
Was genau heißt
Zitat:
jedoch erhalte ich nach dem Laden der "Stream-Datei" eine Fehlermeldung.
?

Benutzt du den Debugger? Was zeigt der Callstack an?
Und stehen in der Nodes nach dem Laden die korrekten Werte?

Auf Anhieb fällt mir nur PointerNodeData auf. Was wird da zugewiesen und wie wird es benutzt? Wenn dies dynamisch allozierter Speicher ist, so ist diese Adresse nach dem Laden (bes. nach Neustart des Programms) natürlich nicht mehr nutzbar.
teamrocket0 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 1

Win ME, Win XP, Win 7, Win 10
Delphi 7, 10.2 Tokyo
BeitragVerfasst: Mi 18.09.24 23:14 
Hallo Th69,

ehm...mit dem Debugger und dem Callstack habe ich bisher noch nicht gearbeitet. :les:

die Fehlermeldung erhalte ich nachdem ich die Stream-Datei geladen habe und irgendwo auf den "VirtualStringTree1" drauf klicke. Egal ob eine leere Stelle, oder dort wo die Nodes angezeigt werden.
Die Nodes werden zumindest namentlich korrekt dargestellt. Meta-Daten kann ich nix zu sagen. Die Fehlermeldung lässt mich nicht mehr mit dem "VirtualStringTree1" interagieren.

Die angezeigte Fehlermeldung hat mich vermuten lassen, das nicht alle Informationen im Stream gespeichert würden. Somit habe ich die "PointerNodeData" hinzugefügt. Damit konnte ich die Fehlfunktion jedoch nicht beheben.
Dieses "PointerNodeData" benutze ich nur an einer Stelle. Bei der Typ-Deklaration für den Record. In der Anleitung "Virtual Treeview step by step" ist auch so ein Pointer eingebaut.

Ich gehe mal davon aus, das die Stream-Datei nicht ordnungsgemäß gespeichert wird.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
type
  // This is a very simple record we use to store data in the nodes.
  // Since the application is responsible to manage all data including the node's caption
  // this record can be considered as minimal requirement in all VT applications.
  // Extend it to whatever your application needs.
  PMyRec = ^TMyRec;
  TMyRec = record
    Caption:        WideString; //Anzeigename im Tree
    ServerAdress:   String;     //Hostname bzw. IP-Adresse in Tabelle schreiben
    Username:       String;     //User-Name
    Domain:         String;     //Domainname
    ClearPW:        WideString; //Klartestpasswort
    wallpaper:      Integer;    //Hintergrundbild anzeigen (std. 0)
    reconnection:   Integer;    //automatisches neu verbinden (std. 1)
    clipboard:      Integer;    //Zwischenablage benutzen (std. 1)
    printers:       Integer;    //Drucker in Remotesitzung benutzen (std. 0)    
    
    PointerNodeData:Pointer;

  end;

_________________
To be forgotten is worse than death!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19284
Erhaltene Danke: 1742

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 19.09.24 08:12 
user profile iconteamrocket0 hat folgendes geschrieben Zum zitierten Posting springen:
ehm...mit dem Debugger und dem Callstack habe ich bisher noch nicht gearbeitet. :les:
Das solltest du ändern, denn das ist sehr wichtig, um Fehler zu finden.

user profile iconteamrocket0 hat folgendes geschrieben Zum zitierten Posting springen:
die Fehlermeldung erhalte ich nachdem ich die Stream-Datei geladen habe und irgendwo auf den "VirtualStringTree1" drauf klicke. Egal ob eine leere Stelle, oder dort wo die Nodes angezeigt werden.
Delphi zeigt diese Fehlermeldung dann ja an. Dann kannst du einfach auf Anhalten drücken und landest dort, wo der Fehler aufgetreten ist. Links oben siehst du, was in welcher Reihenfolge vorher aufgerufen wurde und kannst dich dort durchklicken.

Vermutlich passiert der Fehler in OnGetText oder so, wenn das Laden an sich keinen Fehler produziert.

Ich würde dir aber sehr raten, die Daten unabhängig von der Anzeige zu verwalten. Das ist auch sehr viel einfacher, wenn du die als Json oder XML speicherst, weil die die Inhalte dann auch in einem Texteditor direkt prüfen (und ändern) kannst.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4777
Erhaltene Danke: 1054

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 19.09.24 10:00 
Dann schau dir Tutorial: Debugging in Delphi für Anfänger und Fortgeschr. an (ist zwar für Delphi 2007 geschrieben, grundsätzlich sollte sich aber nicht viel bei neueren Versionen geändert haben - eher verbesserte Benutzung).