delphipointersvirtualtreeviewtvirtualstringtree

Synchronize multiple VirtualStringTrees using 1 copy of data


I have a heirarchy of data that is displayed in a VirtualStringTree. I use this heirarchy multiple times in my application with slight modifications to the way the tree is drawn/displayed. My method currently utilizes the AddChild() procedure for adding nodes an d as such i have multiple copies of the data when the application is run.

I would now like to consolidate these trees and have a 'master' tree which points to the actual data, but then have the 'slave' trees point to the SAME data.

I am a little unsure of if/how this can be acheived. I would think i could simply load the master tree and populate its NodeData with pointers to where the data i being held, and then for all the slave trees, simply store the same pointer in their nodedata.

However im not having much luck.

My current code looks like:

//Initialize the NodeDataSize
procedure TForm1.FormCreate(Sender: TObject);
begin
     TreeMasterComponents.NodeDataSize := SizeOf(rMasterComponent);
     VST.NodeDataSize := SizeOf(Pointer);
end;

Procedure to copy the master tree to slave trees

procedure TForm1.LoadSlaveTree(ATree: TVirtualStringTree);
var Node : PVirtualNode;

procedure RecursiveCopy(SrcPNode,SrcTNode : PVirtualNode; ATree : TVirtualStringTree);
var SrcNode, TargetNode : PVirtualNode;
SrcData : PMasterComponent;
begin
     SrcNode := TreeMasterComponents.GetFirstChild(SrcPNode);
     while Assigned(SrcNode) do
     begin
          SrcData := TreeMasterComponents.GetNodeData(SrcNode);
          TargetNode := ATree.AddChild(SrcTNode,SrcData);
          RecursiveCopy(SrcNode,TargetNode,ATree);
          SrcNode := SrcNode.NextSibling;
     end;
end;

begin
     ATree.BeginUpdate;
     ATree.Clear;
     Node := TreeMasterComponents.GetFirst(true);
     while Assigned(Node) do
     begin
         RecursiveCopy(Node,nil,ATree);
         Node := Node.NextSibling;
     end;
     ATree.EndUpdate;
end;

Procedure for slave tree to getCellText

procedure TForm1.SlaveGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var Data : PMasterComponent;
begin
     Data := Sender.GetNodeData(Node);
     Case column of
     0:CellText := Data^.ComponentCode;
     1:CellText := Data^.FullLocation;
     end;
end;

At the moment, the nodes are added in the correct heirarchy, however there is no text appearing for the slave trees. Any help would be appreciated.


Solution

  • Ok so i beleive i have found a solution:

    The trick was to create a new record to store the Pointer to the original data:

    type PRefMasterComponent = ^RefMasterComponent;
      RefMasterComponent = packed record
         PMCData : PMasterComponent;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
         TreeMasterComponents.NodeDataSize := SizeOf(rMasterComponent);
         VST.NodeDataSize := SizeOf(RefMasterComponent);
    end;
    

    Now the Copy code looks like:

    procedure TForm1.LoadTree(ATree: TVirtualStringTree);
    var Node,TargetNode : PVirtualNode;
    SrcData : PMasterComponent;
    Data : PRefMasterComponent;
    
    procedure RecursiveCopy(SrcPNode, TargetPNode : PVirtualNode; ATree : TVirtualStringTree);
    var Node, TargetNode : PVirtualNode;
    SrcData : PMasterComponent;
    Data : PRefMasterComponent;
    begin
         Node := TreeMasterComponents.GetFirstChild(SrcPNode);
         while Assigned(Node) do
         begin
              SrcData := TreeMasterComponents.GetNodeData(Node);
              TargetNode := ATree.AddChild(TargetPNode);
              Data := ATree.GetNodeData(TargetNode);
              Data.PMCData := SrcData;
              RecursiveCopy(Node,TargetNode,ATree);
              Node := Node.NextSibling;
         end;
    end;
    
    begin
         ATree.BeginUpdate;
         ATree.Clear;
         Node := TreeMasterComponents.GetFirst(true);
         while Assigned(Node) do
         begin
              SrcData := TreeMasterComponents.GetNodeData(Node);
              TargetNode := ATree.AddChild(nil);
              Data := ATree.GetNodeData(TargetNode);
              Data.PMCData := SrcData;
              RecursiveCopy(Node,TargetNode,ATree);
              Node := Node.NextSibling;
         end;
         ATree.EndUpdate;
    end;
    

    and the OnGetText:

    procedure TForm1.vstGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
    var Data : PRefMasterComponent;
    RefData : PMasterComponent;
    begin
         Data := Sender.GetNodeData(Node);
         RefData := Data.PMCData;
         Case column of
         0:CellText := RefData.ComponentCode;
         1:CellText := RefData.FullLocation;
         end;
    end;
    

    Now if i change data in one tree all i have to do is call VST.Invalidate and the changes are reflected in the other tree.