VirtualTreeView copy tree with data

删除回忆录丶 提交于 2019-12-12 05:49:43

问题


How to copy all nodes from one VirtualTreeView to another? I tried to use CopyTo-function, but the Data was empty, why? Data contains reference to record (as usual).

I've also tried to use the OnNodeCopying event as @Cosmin Prund suggested in his now deleted answer this way, but it crashes:

procedure TDataBaseForm.SourceTreeViewNodeCopying(Sender: TBaseVirtualTree; 
  Node, Target: PVirtualNode; var Allowed: Boolean); 
var 
  SourceNodeData, DestNodeData: PNodeDataForCompare; 
begin 
  SourceNodeData := Sender.GetNodeData(Node); 
  DestNodeData := VirtualStringTree1.GetNodeData(Target); 
  if Assigned(SourceNodeData) then 
  begin 
    DestNodeData^ := SourceNodeData^; 
  end; 
  Allowed := true; 
end;

回答1:


I've dug a bit deeper into how the CopyTo() works. All the nodes to be copied are first saved to a stream, next the nodes from the stream are re-created on the target VirtualTree. The user node data needs to be copied into that stream, or else it will not be available when re-creating the nodes in the target VirtualTree.

The events that handle streaming user data are:

  • OnSaveNode
  • OnLoadNode

It makes sense for the VirtualTree to make use of those methods, and as a consequence makes sense to use the stream as an intermediary object. The VirtualTree also allows saving the tree to a file and copy-pasting nodes to and from clipboard. All those methods need to somehow copy the user's "payload"! After implementing those events the CopyTo method worked fine, so did saving the the content of the first tree to disk and re-loading it into the second tree. I also tested copy-pasting and it worked fine.

Here's my implementation of the OnSaveNode and OnLoadNode. Copy-pasting my methods will most likely not work for you, because it depends on the kind of data you put in the node payload. In my example I placed records (not pointers-to-records) made up of just one Integer: those records can safely be streamed to disk and reloaded, they're not managed types, they're simple value types. If you're placing pointers into the records (reference-to-records as you called them) you can still use this and it will work, but you'd be copying POINTERS: You don't get new records, they're the same records; you obviously can't save the Tree to a file, restart the program and reload from disk.

procedure TForm6.VT1SaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Stream: TStream);
begin
  Stream.Write(Sender.GetNodeData(Node)^, (Sender as TVirtualStringTree).NodeDataSize);
end;

procedure TForm6.VT2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
begin
  CellText := IntToStr(PNodeDataForCompare(VT1.GetNodeData(Node)).Payload);
end;

One final note: For your scenario you'll need the OnSaveNode implemented on the Source tree and the OnLoadNode implemented on the Target tree; I implemented them on both using the same code.




回答2:


unit VirtualTrees;

...

function TBaseVirtualTree.CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean): PVirtualNode;

...

        Result := TargetTree.MakeNewNode;
        InternalConnectNode(Result, Target, TargetTree, Mode);
        TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, Result);
        if not DoNodeCopying(Result, Source {Target}) then //        <=======
        begin
          TargetTree.DeleteNode(Result);
          Result := nil;
        end

...



来源:https://stackoverflow.com/questions/14910000/virtualtreeview-copy-tree-with-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!