Delphi what is the Ideal method to populate a VirtualStringTree?

So I'm working with Delphi 2010 and it's been a while since I began using the VirtualTreeView (precisely VirtualStringTree)..and it seems that I'm doing something in a wrong way..since things aren't working as I'm expecting.

I'm trying to populate my VST with nodes that point to files/subfolders descriptions stored in records of data and generated by scanning a path given by the user..(more details are shown in the following image)

在这里输入图像描述

As it shown nodes are shown in weird way..& no matter what I do nodes data aren't initialized properly..nodes captions for column "File" is the only thing that work well.

& here's the code I use:

1- Node data declaration :

type  nodeData=record
            Text, Size, Path:String;
            ImageIndex:Integer;
           end;

  PNodeData=^nodeData;


var hashmap:TDictionary<String, PVirtualNode>; // hashmap-> to store parent nodes (Folder)
    filesList:TDictionary<Integer,nodeData>; // fileList to store records of data

2- Methods

a) scan a path given by the user

procedure AddAllFilesInDir(const Dir:String);
begin
// it scans the path 'Dir' and extract the "name & size" of each file/folder found in this dir
end;

b) generate the filesList tdictionary... & images are stored in " treeImageLIst " which is linked to the treeview.images property

procedure addFileToList(Name, Size:String);
var d:nodeData;
    parent:String;
    SHFileInfo :TSHFileINfo;
    Icon:TIcon;
begin
parent:=ExtractFileDir(Name);

//Get The Icon That Represents The File/Folder
SHGetFileInfo(PChar(Name), 0, SHFileInfo,  SizeOf(SHFileInfo),
                SHGFI_ICON or SHGFI_SMALLICON );


Icon := TIcon.Create;
Icon.Handle := SHFileInfo.hIcon;

// set The Name, Size, Path
d.Name:=ExtractFileName(Name);
d.Size:=Size;
d.Path:=parent;

// set the ImageIndex
d.ImageIndex:=Form1.treeImageList.AddIcon(Icon);

// add the node to fileList
filesList.Add(filesList.Count, d);

// Destroy the Icon
DestroyIcon(SHFileInfo.hIcon);
Icon.Free;
end;

c) create the tree "theTree"

procedure createTree();
var theNode, Node:PVirtualNode;
    d:PNodeData;
    parent:String;
    nData:nodeData;
    i:integer;
begin

for i := 0 to filesList.Count - 1 do
begin

 nData:=filesList.Items[i];  parent:=nData.Path;

 if(hashmap.ContainsKey(parent))then theNode:=hashmap.Items[parent]
 else theNode:=nil;

 Node:=Form1.theTree.AddChild(theNode);

 // add a checkbox and make it checked
 Node.CheckType:=ctCheckBox;
 Node.CheckState:=csCheckedNormal;

 // get the newly created node data
 d:=Form1.theTree.GetNodeData(Node);

 // assign a data  to the newly created node
 d^:=nData;

 // add the node to hashmap if it's a new folder node
 if((ExtractFileExt(nData.Text)='')and(not hashmap.ContainsKey(nData.Path+''+nData.Text)))
 then hashmap.Add(nData.Path+''+nData.Text, Node);

end;

 Form1.theTree.Expanded[Form1.theTree.TopNode]:=True;
end;

d) the treeview events

procedure TForm1.theTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var d:PNodeData;
begin
  d := Sender.GetNodeData(Node);
  Finalize(d^);
end;


procedure TForm1.theTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var d:PNodeData;
begin
 d:=Sender.GetNodeData(Node);

 case Column of
  0:CellText:=d^.Text;
  1:CellText:=d^.Size;
 end;
end;


procedure TForm1.theTreeGetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);

var d:PNodeData;
begin
d:=Sender.GetNodeData(Node);

if(Kind in [ikNormal, ikSelected])then
begin
 if(Column=0)then ImageIndex:=d^.ImageIndex;
end;

end;

I'm really frustrated right now..and I don't know why nodes arent created properly..although I tested the records data & they are created well but when I test the onNodeClick event I found that the data record pointed by the Node returns only the first field ..while the other fields are either empty or they generate an Access violation exception .


You have posted entirely too much code to make a useful question. There are hundreds of questions posted every day which have no code samples, or not enough code samples. You have gone the other way, really far the other way.

The best way to "populate" a virtual tree view is to NOT populate it. Instead you only set the rootNodeCount and then iteratively, when you have to, set the child node counts for the child nodes. For a collapsed node, it is enough that the tree view knows that there are children, or that there are not. Once you expand a childnode, you can populate the sub-elements.

Note that when you do it the way Virtual Controls are meant to be done, you are not writing a tonne of code. Instead you are simply "answering questions about the underlying state of your model objects". How many root nodes are there? You tell virtual tree that number. Then from there, you simply answer questions when it asks you. What is the text for column 0, for node #3 under the root node? (It invokes an event which you handle, and you return that information). Note that initializing the DATA is something that most people who are new to VirtualTreeViews often misunderstand. Ideally that DATA should contain a pointer to a real model object that can answer the questions that VirtualTreeView asks it. The most efficient classes that answer those questions might not even need to instantiate a real model object for each visible node in the tree, although that's certainly acceptable and common. It's important that you understand that it's not strictly ESSENTIAL though.

Secondly, if your goal was to use the TVirtualTreeView to emulate a shell explorer, that code is already done for you, look at the sub-section of the Advanced VT demo is available from the VirtualTreeview website. See the tab I have indicated here:

在这里输入图像描述

链接地址: http://www.djcxy.com/p/35002.html

上一篇: 在鼠标点击和键盘节点选择上执行代码

下一篇: Delphi什么是填充VirtualStringTree的理想方法?