282 lines
9.6 KiB
TeX
282 lines
9.6 KiB
TeX
@@Repositiory.htm
|
|
<TITLE A little code repository by John Knipper>
|
|
|
|
This is just written by me John Knipper. Don't bother Mike if something is wrong here. I am not related to Mikes company
|
|
in any way. I'm just doing that because I believe so much in his component, that I would not give you the possibility to
|
|
miss the opportunity to use it. You won't regret it. I'm not going to enumerate all the nice advantage it has on it's
|
|
competitors. Because it has so many. The biggest I see is the speed improvement, the multi columns, the automatic
|
|
allocation of node data and so many more.
|
|
|
|
|
|
|
|
You will see that the strong points of the Virtual tree view are not obvious. But you can believe me, this is the best
|
|
Treeview ever. You will be kinda lost at the beginning, but it's only a matter of forgetting what you know about trees.
|
|
This is the right way to do it. You will ask yourself why it has not be done like that at the beginning.
|
|
|
|
<B>
|
|
|
|
|
|
|
|
Q: How to initially fill the tree?
|
|
|
|
A:</B> The only information VT needs at startup is the number of root nodes. All other information is queried from the
|
|
application when they are needed (text, node height etc.). Hence all to do is to set property RootNodeCount to the number
|
|
\of nodes required.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
VirtualStringTree1.RootNodeCount := 5; <COLOR Blue>// is adding 5 nodes at the root of your tree</COLOR>
|
|
</CODE>
|
|
|
|
|
|
To initialize the nodes, use the OnInitNode event
|
|
|
|
<B>
|
|
|
|
|
|
|
|
Q: How to add a node to the tree?
|
|
|
|
A:</B> The technique is very similar to the one you used with the standard tree view. The only difference is that you
|
|
fill the node's data after the insertion of the node
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
<B>var</B>
|
|
Node: PVirtualNode;
|
|
Node := VirtualStringTree1.AddChild(<B>nil</B>); <COLOR Blue>// Adds a node to the root of the Tree.</COLOR>
|
|
Node := VirtualStringTree1.AddChild(ParentNode); <COLOR Blue>// Adds a node as the last child of the given node.</COLOR>
|
|
Node := VirtualStringTree1.InsertNode(Node, amInsertBefore); <COLOR Blue>// Inserts a node as sibling just before the given node.</COLOR>
|
|
</CODE>
|
|
|
|
|
|
Alternatively you can use the OnInitChildren event. This event is used when a node is marked as having child nodes and
|
|
these child nodes are somehow about to be accessed (like iteration, expanding, display etc.).
|
|
|
|
<B>
|
|
|
|
|
|
|
|
Q: Where is gone all the information about my node, like text for example ?
|
|
|
|
A:</B> The text property is gone. You don't need it anymore. The basic idea behind Virtual Treeview is to leave all data
|
|
management to the application which knows much better how to do this than the tree (see also Related Topics). Every node
|
|
knows which is its parent and which are their children. Information like the text property, the new hint property, the
|
|
ImageIndex property and everything else should be stored in the node's data. The tree will ask for it on demand, e.g.
|
|
when it needs to show a certain node etc.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
TTreeData = <B>record</B>
|
|
Text: WideString;
|
|
URL: <B>String</B>[255];
|
|
CRC: LongInt;
|
|
isOpened: Boolean;
|
|
ImageIndex: Integer;
|
|
<B>end</B>;
|
|
PTreeData = ^TTreeData; <COLOR Blue>// This is a node example.</COLOR>
|
|
</CODE>
|
|
<B>
|
|
|
|
|
|
|
|
Q: When should I allocate memory for the node data?
|
|
|
|
A:</B> Never, the VT does it for you. The only thing you have to do is to tell the VT how much memory you need for your
|
|
node data.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
VirtualStringTree1.NodeDataSize := SizeOf(TTreeData); <COLOR Blue>// The nodes are reinitialized when you change that value.</COLOR>
|
|
</CODE>
|
|
|
|
|
|
If you know how much memory it will take, you can use the NodeDataSize property of the VT and initialize it directly at
|
|
design time.
|
|
|
|
|
|
|
|
<B>
|
|
|
|
Q: When should I fill my nodes data?
|
|
|
|
A:</B> The ideal place for this is the OnInitNode event.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
<B>procedure</B> TMainForm.VTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; <B>var</B> InitialStates: TVirtualNodeInitStates);
|
|
|
|
<B>var</B>
|
|
Level: Integer;
|
|
Data,
|
|
ParentData: PMyNodeData;
|
|
Count: Integer;
|
|
|
|
<B>begin</B>
|
|
<B>with</B> Sender <B>do</B>
|
|
<B>begin</B>
|
|
Data := GetNodeData(Node);
|
|
ParentData := GetNodeData(ParentNode);
|
|
if Assigned(ParentData) <B>then</B> Level := ParentData.Level + <COLOR Pink>1</COLOR>
|
|
<B>else</B> Level := <COLOR Pink>0</COLOR>;
|
|
|
|
<B>case</B> FFillMode <B>of</B>
|
|
<COLOR Pink>0</COLOR>: <COLOR Blue>// fill tree with a specific amount of nodes and levels</COLOR>
|
|
<B>begin</B>
|
|
// determine new node level
|
|
if Level \< (LevelsUpDown.Position - <COLOR Pink>1</COLOR>) then Include(InitialStates, ivsHasChildren);
|
|
<B>end</B>;
|
|
<COLOR Pink>1</COLOR>: <COLOR Blue>// fill tree with one million root nodes (nothing special to do here)</COLOR>
|
|
;
|
|
<COLOR Pink>2</COLOR>: <COLOR Blue>// fill tree with a certain amount of root nodes (they always get fixed text to test sorting)</COLOR>
|
|
<B>begin</B>
|
|
Data.FixedText := True;
|
|
Data.NewText := Format(<COLOR Pink>'Node: %d'</COLOR>, [Node.Index]);
|
|
<B>end</B>;
|
|
<COLOR Pink>3</COLOR>: <COLOR Blue>// fill tree with a certain amount of root nodes and a random amount of child nodes
|
|
// up to an absolute amount of ~1 million nodes and with at most 10 levels</COLOR>
|
|
<B>begin</B>
|
|
<B>if</B> Assigned(ParentNode) <B>then</B> Count := ParentNode.ChildCount
|
|
<B>else</B> Count := TVirtualStringTree(Sender).RootNodeCount;
|
|
<B>if</B> (Level \< 15) <B>and</B>
|
|
(Random(Count) \< (Count <B>div</B> <COLOR Pink>2</COLOR>)) <B>and</B>
|
|
(FCurrentCount \< <COLOR Pink>1000000</COLOR>) <B>then</B> Include(InitialStates, ivsHasChildren);
|
|
<B>end</B>;
|
|
<B>end</B>;
|
|
|
|
Data.Level := Level;
|
|
Node.CheckType := ctTriStateCheckBox;
|
|
<B>case</B> Level <B>of</B>
|
|
<COLOR Pink>1</COLOR>:
|
|
if Random(<COLOR Pink>5</COLOR>) \< <COLOR Pink>2</COLOR> then Include(InitialStates, ivsDisabled);
|
|
<B>end</B>;
|
|
<B>end</B>;
|
|
<B>end</B>;
|
|
</CODE>
|
|
<B>
|
|
|
|
|
|
|
|
Q: How do I access a node's data?
|
|
|
|
A:</B> Use GetNodeData(Node) to get a pointer on your nodes data
|
|
|
|
<B>E:</B> Either use
|
|
<CODE>
|
|
<B>with</B> PTreeData(VirtualStringTree1.GetNodeData(Node))^ <B>do
|
|
begin</B>
|
|
Text:= ChangeFileExt(ExtractFileName(FileName), <COLOR Pink>''</COLOR>);
|
|
ImageIndex:= <COLOR Pink>1</COLOR>; <COLOR Blue>//it's an example ;)</COLOR>
|
|
<B>end</B>;
|
|
</CODE>
|
|
Or in that case you can use
|
|
<CODE>
|
|
<B>var</B>
|
|
NodeData: PTreeData;
|
|
|
|
<B>begin</B>
|
|
NodeData := VirtualStringTree1.GetNodeData(Node);
|
|
NodeData.Text := <COLOR Pink>'a test'</COLOR>;
|
|
NodeData.ImageIndex := <COLOR Pink>1</COLOR>;
|
|
...
|
|
</CODE>
|
|
<B>
|
|
|
|
|
|
|
|
Q: What else can I do with that nodes data pointer?
|
|
|
|
A:</B> Usually you already have all data in your own structure (database, file etc.) so you need only to supply an
|
|
identifier or a pointer into your own structure. This prevents your application from doubling the data just for display
|
|
which in turn saves a remarkable amount of memory.
|
|
|
|
<B>E:</B> You could connect a TBookmark to the data. To display the name of your customer in a VT :
|
|
<CODE>
|
|
<B>procedure</B> TFRM_WWW_main.vFavTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: Integer; TextType: TVSTTextType; <B>var</B> Text: WideString);
|
|
<B>
|
|
begin</B>
|
|
<COLOR Blue>// Column is -1 if the header is hidden or no columns are defined</COLOR>
|
|
<B> if</B> Column \< <COLOR Pink>0</COLOR> <B>then</B> Exit;
|
|
<B> if</B> TVirtualStringTree(Sender).Header.Columns[Column].Text = <COLOR Pink>'Customer Name'</COLOR> <B>then
|
|
begin</B>
|
|
Table.GotoBookmark(TBookmark(Sender.GetNodeData(Node)));
|
|
Text := Table.FieldByName(<COLOR Pink>'Name'</COLOR>).asString;
|
|
<B> end</B>;
|
|
<B>end</B>;
|
|
</CODE>
|
|
<B>
|
|
|
|
Q: A move of a scrollbar's thumb doesn't directly scroll the tree. What to do?
|
|
|
|
A:</B>
|
|
<CODE>
|
|
VirtualStringTree1.VertScrollBar.Track := True;
|
|
</CODE>
|
|
<B>
|
|
|
|
|
|
|
|
Q: How can I display text for other columns?
|
|
|
|
A:</B> In the OnGetText event, check the column index.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
<B>procedure</B> TFRM_WWW_main.vFavTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: Integer; TextType: TVSTTextType; <B>var</B> Text: WideString);
|
|
<B>
|
|
begin
|
|
case</B> Column <B>of</B>
|
|
\-1, <COLOR Blue>// main column, -1 if columns are hidden, 0 if they are shown</COLOR>
|
|
0:
|
|
Text := <COLOR Pink>'Text of column 1'</COLOR>;
|
|
1:
|
|
Text := <COLOR Pink>'Text of column 2'</COLOR>;
|
|
2:
|
|
Text := <COLOR Pink>'Text of column 3'</COLOR>;
|
|
<B> end</B>;
|
|
<B>end</B>;
|
|
</CODE>
|
|
<B>
|
|
|
|
Q: When do I tell which icon to use?
|
|
|
|
A:</B> It's the same principle as for the OnGetText event. With the exception that you must tell which icon to use in 3
|
|
cases: the normal icon, the selected icon and the state icon.
|
|
|
|
<B>E:</B>
|
|
<CODE>
|
|
<B>procedure</B> TFRM_WWW_main.vFavTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: Integer; <B>var</B> <B>Index</B>: Integer);
|
|
<B>
|
|
begin
|
|
if</B> Kind = ikState <B>then
|
|
begin
|
|
</B>Index := <COLOR Pink>2</COLOR>;
|
|
<B> end
|
|
else
|
|
if</B> (Kind = ikNormal) <B>or</B> (Kind = ikSelected) <B>then
|
|
begin
|
|
</B>Index := <COLOR Pink>1</COLOR>;
|
|
<B> end</B>;
|
|
<B>end</B>;
|
|
</CODE>
|
|
\or just use
|
|
<CODE>
|
|
<B>procedure</B> TFRM_WWW_main.vFavTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: Integer; <B>var</B> <B>Index</B>: Integer);
|
|
<B>
|
|
begin
|
|
case</B> Kind <B>of</B>
|
|
ikState:
|
|
<B> Index</B> := <COLOR Pink>2</COLOR>;
|
|
ikNormal,
|
|
ikSelected:
|
|
<B> Index</B> := <COLOR Pink>1</COLOR>;
|
|
<B> end</B>;
|
|
<B>end</B>;
|
|
</CODE>
|
|
|
|
|
|
|
|
|
|
Ok, here we are. This is only a small introduction to help you begin with Virtual Treeview. There are many more useful
|
|
functions. Nearly everything was done for you. Thank you very much for your work Mike.
|