Virtual Treeview使用要點
Virtual Treeview是一套Delphi下優秀的VCL控件,代碼質量高,使用靈活、功能強大、性能非常好,可以用於表達Treeview和表格類數據。它的代碼現在托管在google code上。
這套控件使用了很久了,非常滿意其表現,之前一直使用V4版,現在V5正式發布了,新版花了幾年時間進行重構, 代碼結構更加合理,去除了老版大量的小缺陷,很多功能進行了重新設計,參與維護的人也更多了。
Virtual Treeview的設計思路與官方的Treeview完全不一樣,VT是基於高性能和更豐富的表現而開發的,在上手方面比Treeview要慢一些,但一旦上手,就會發現非常好用。
在使用VT之前,就應該設計好以什麽方式展示數據,每個節點應該有些什麽屬性。在構思好後,就可以按以下步驟來實現VT的使用了。
1、節點數據
在實際使用Virtual Treeview之前,應該先設計好一個節點數據的結構體,用於方便每個節點的展示。
比如一個典型的設計如下:
PTreeData = ^TTreeData;
TTreeData = record
Level: integer; // 節點級別:0根;1節點;2參數
NodeType: integer; // 節點類型
Id: Integer; // 數據id
Caption: String; // 節點標題
obj : TObject; // 節點對應的對象或空
end;
其中Caption用於控制節點顯示,Id用於方便節點對應數據的快速定位,obj用於把節點與相關的對象關聯在一起,其它數據也是用於方便進行數據處理的。
2、列的處理
一般情況下,如果是只當成普通Treeview,無需考慮列(Column)的處理,直接使用即可。如果一行有多列數據需要顯示,則得先在屬性Header-Columns中增加所需的列,並設置合適的列寬。缺省列(Column)設置為空,列索引(TColumnIndex)應該為-1,在設置了列後,第一列的列索引為0,第二列的列索引為1。
3、第一個節點
在樹中的所有節點中,只有根節點的父節點為空(nil)。創建根節點的示例代碼如下:
var
Data : PTreeData;
Node: PVirtualNode;
RootNode: PVirtualNode;
vst.Clear; // 清除所有節點
vst.NodeDataSize := Sizeof(TTreeData); // 設置節點數據大小
RootNode := vst.AddChild(nil); // 增加一個根節點
vst.ValidateNode(RootNode, false);
Data := vst.GetNodeData(RootNode); // 獲取節點數據
Data.Caption := ‘根節點1‘; // 設置將要顯示在節點的文本信息
4、多級節點
創建完全根節點後,就可以在根節點後增加各級子節點了。
Node := vst.AddChild(RootNode); // 增加一級子節點
data := vst.GetNodeData(Node); // 獲取節點數據
data.Level := vst.GetNodeLevel(Node); // 設置節點級別,方便後繼處理
Node := vst.AddChild(Node); // 增加二級子節點
data := vst.GetNodeData(Node);
data.Level := vst.GetNodeLevel(Node);
Node := vst.AddChild(RootNode); // 再增加一個一級子節點
data := vst.GetNodeData(Node);
data.Level := vst.GetNodeLevel(Node);
// 當然這裏可以批量產生多個子節點,比如
// for i:=0 to 99 do
// begin Node := vst.addchild(rootNode); ... end;
vst.FullExpand(RootNode); // 把根節點下的所有子節點打開
上面只是簡單示例,完整示例中需要把節點數據都設置完整。
這裏還有一種方式進行更高速的創建子節點,比如:
vst.ChildCount[RootNode] := 100;
這樣,就可以一下給根節點設置100個一級子節點。當然,這些節點的數據都還是缺省狀態,我們可以在適當的時候和適當的位置再進行設置。
如果我們需要一次插入多個節點,為了提高顯示效率,我們應該在插入前調用BeginUpdate,在插入完成後再調用EndUpdate。
5、顯示節點內容
運行後,可以發現樹的確出來了,但所有節點顯示的都是似乎"Node"字樣的東西,怎麽樣把我們需要顯示的內容顯示出來?
我們需要設置Virtual Treeview的GetText事件,VT在顯示節點信息時會調用GetText來獲取要顯示的內容。我們可以增加類似下面的代碼:
procedure TfrmMain.vstGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
Data : PTreeData;
begin
CellText := ‘‘;
Data := vst.GetNodeData(Node);
if not Assigned(Data) then
exit;
Case Data.Level of
0:
begin
CellText := Data.Caption;
end;
1:
begin
CellText := format(‘一級子節點‘,[]);
end;
2:
begin
CellText := format(‘二級子節點‘,[]);
end;
end;
end;
當然,實際代碼要復雜的多。而且這個代碼並沒有處理多列的情況,如果有多列就得針對各列再加一級case語句就可以了。也就是說類似這樣的代碼,假設我們設置了一個節點有三列:
procedure TfrmMain.vstGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
Data : PTreeData;
begin
CellText := ‘‘;
Data := vst.GetNodeData(Node);
if not Assigned(Data) then
exit;
Case Column of
0: // 第一列的處理
begin
Case Data.Level of
0:
begin
CellText := Data.Caption;
end;
1:
begin
CellText := format(‘一級子節點‘,[]);
end;
2:
begin
CellText := format(‘二級子節點‘,[]);
end;
end;
end;
1: // 第二列的處理
begin
// 一般是取Data中obj對象,再取其中的數據用於處理顯示
end;
2: // 第三列的處理
begin
// 一般是取Data中obj對象,再取其中的數據用於處理顯示
end;
end;
end;
也就是說vst各節點的內容,其實都是通過代碼來控制並設置的。無論是Treeview形式還是表格形式或兩者綜合體,數據的顯示都是這麽處理的。
5、節點圖標
經常我們需要在每個節點前加個小圖標,可用於表達這個節點的狀態、類型或純美觀。Virtual Treeview顯示圖標一樣也是要與TImageList配合使用的。我們需要先在一個ImageList中加載上合適的所有圖標,然後在GetImageIndex事件中進行判斷處理每個節點應該使用的圖標的索引來加載ImageList中的圖標。
比如:
procedure TfrmMain.vstGetImageIndex(Sender: TBaseVirtualTree;
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
var Ghosted: Boolean; var ImageIndex: Integer);
var
Data : PTreeData;
begin
Data := vst.GetNodeData(Node);
if not Assigned(Data) then
exit;
Case Data.Level of
0:
begin
ImageIndex := 2;
end;
1:
begin
ImageIndex := 0;
end;
2:
begin
ImageIndex := 0;
end;
end;
end;
6、節點數據空間的清理
在Virutal Treeview組件釋放時,我們應該同時清理掉每個節點對應的數據空間。我們應該在FreeNode事件中寫上以下類似的代碼來完成這個工作:
procedure TfrmMain.vstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); var Data : PTreeData; begin Data := vst.GetNodeData(Node); if Assigned(Data) then begin Data.Caption := ‘‘; // String must be cleaned manual, otherwise there is memory leak // 節點數據記錄中對應的數據對象,不一定得在這釋放,可以在其它地方統一處理 //FreeAndNil(Data.obj);
end; end;
節點數據空間不需要我們釋放,在前面對vst初始化時寫過這麽一句代碼:
vst.NodeDataSize := Sizeof(TTreeData); // 設置節點數據大小
這裏就是初始化節點數據記錄空間的,這個空間會被vst自動釋放。但這個記錄體中的類似字符串或指針所指向的內存空間或對像是不會被自動釋放的。所以,這裏我們把Data.Caption字符串清空,以避免內存泄漏。
Virtual Treeview使用要點