例子:建立了一個樹名爲VirtualStringTree1,第一列顯示數據庫字段ID的值,標題爲編號;第二列顯示字段Name的值,標題爲名字。
1、【TVirtualStringTree經常使用屬性】
BorderStyle :設置邊框選項 bsSingle設置單邊框
爲TVirtualStringTree添加列及列標題:
Header--Columns : 設置列 點擊「…」,在彈出界面點擊add new按鈕,就增長一列,在其text中輸入列名,在width輸入列寬度;
Header--options-hovisible: 設置列可顯示!! node
Header-Style :設置樹的主題類型
ScrollBaroptions--AlwaysVisible 滾動條是否老是可見
ScrollBarOptions-ScrollBars-ssVertical 設置爲只有豎向滾動條
爲TVirtualStringTree添加勾選框、選擇框、複選框:
TreeOptions----MiscOpitions---toCheckSupport 設置爲True便可
CheckImageKind 爲勾選框設置圖標sql
Header-Maincolumn 設置勾選框在第幾列前面,默認爲0也就是在第一列前面數據庫
並設置ongettext()事件和onInitailNode()事件,見下面事件部分。函數
--------------------------------------------------------------------------------------------------------------------------------------------字體
2、 【TVirtualStringTree經常使用方法 】
VirtualStringTree1.NodeDataSize := sizeOf(TMyNodeData); //設置佔存儲空間大小指針
樹節點選中:VirtualStringTree1.Selected[p_node]True; //設置節點p_node處於選中狀態orm
樹節點勾選框選中:p_node.CheckState:=cscheckedNormal;//設置節點p_node處於勾選狀態事件
onchecked()事件:設置節點勾選時觸發的事件,其中第二個參數就是勾選的節點ci
取消選中的節點:VirtualStringTree1.ClearSelection;get
樹節點刪除: VirtualStringTree1.DeleteSelectedNodes; //刪除選中的節點
樹節點內容清空:VirtualStringTree1.clear;
獲得樹的第一個節點:VirtualStringTree1.GetFirst;
獲得樹的第一個選中節點:VirtualStringTree1.GetFirstSelected;
獲得節點的下一個節點:VirtualStringTree1.Getnext(p_node);
獲得下一個選中的節點:VirtualStringTree1.GetNextSelected(p_node);
獲得父節點:p_node.Parent
獲得子節點個數:p_node.ChildCount
獲得第一個子節點:p_node.FirstChild
獲得最後一個子節點:p_node.FirstChild
獲得上一個兄弟節點:p_node.PrevSibling
獲得下一個兄弟節點:p_node.NextSibling
---------------------------------------------------------------------------------------------------------------------------
3、【TVirtualStringTree顯示數據庫字段內容】:
//定義一個指針
type
Tjdtransline =record
id: integer; //編號
name : string; //名稱
levelID : integer;//級別,例如總公司levelID 爲0、二級公司爲一、三級公司levelID 爲2等
FatherID:integer; //節點的父節點ID
end;
pjdtransline =^Tjdtransline ;
private
procedure iniVirtualStringTree1; //事件聲明爲全局私有事件
//樹顯示數據庫字段內容
procedure form1.iniVirtualStringTree1;
var
p_jdtransline: pjdtransline;
begin
while not adoquery1.Eof do
begin
New(p_jdtransline);
p_jdtransline^.ID := client_dataset_jdtransline.FieldByName('ID').AsInteger;
p_jdtransline^.Name := Trim(client_dataset_jdtransline.FieldByName('Name').AsString);
VirtualStringTree1.AddChild(nil, p_jdtransline); //*********************添加樹節點***********************************
adoquery1.Next;
end;
end;
//在窗體建立時調用樹的初始化事件
procedure form1.formcreate(sender:Tobject);
begin
iniVirtualStringTree1;
end;
//設置各列字段的顯示OnGetText() var
p_node_data : PMyNodeData;
p_jdtransline : PJDTranslineTree;
begin
p_node_data := VirtualStringTree1.GetNodeData(Node);
p_jdtransline := p_node_data^.my_data_ptr;
case Column of
0 : CellText := inttostr( p_jdtransline^.ID);
1: CellText := p_jdtransline^.Name;
end;
end;
------------------------------------------------------------------------------------------------------------------------------------
4、 【TVirtualStringTree設置節點展開與摺疊的圖標 】
OnInitNode() //設置結點的節點是否有子節點類型(‘+’、‘—’顯示)
begin
Include(InitialStates, ivsHasChildren);
Node.CheckType := ctTriStateCheckBox;
end;
-------------------------------------------------VirtualStringTree樹拖動操做實現開始-------------------------------------------------------------------------
5、【VirtualStringTree樹節點拖動實現】
主要設置其DragOver和DragDrop事件。其中DragOver控制是否容許移動;DragDrop控制移動後執行的操做。
//1、DragOver事件
procedure form1.VirtualStringTree1Over(
Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState;
State: TDragState; Pt: TPoint; Mode: TDropMode; var Effect: Integer;
var Accept: Boolean);
//事件內部函數1.獲取節點的值
function GetVNodeData(vn: PVirtualNode; vst: TVirtualStringTree): PVNodeData;
begin
Result := PVNodeData(PPointer(vst.GetNodeData(vn))^);
end;
//事件內部函數2.獲取全部選中節點的列表
function GetSelectedVNodes(vst: TVirtualStringTree): TVNodeArray;
var
list: TList;
n: PVirtualNode;
i: Integer;
begin
list := TList.Create;
n := vst.GetFirstSelected;
while n <> nil do
begin
list.Add(n);
n := vst.GetNextSelected(n);
end;
SetLength(Result, list.Count);
for i := 0 to list.Count-1 do
begin
Result[i] := list[i];
end;
list.Free;
end;
// //事件內部函數3.判斷是不是移動到本身的父節點
function IsSameLevel(selectedList: TVNodeArray): Boolean;
var
n: PVirtualNode;
l: Cardinal;
i: Integer;
begin
Result := False;
if Length(selectedList) = 0 then
begin
Result := True;
Exit;
end;
for i := 0 to High(selectedList) do
begin
n := selectedList[i];
if n.Parent = Sender.DropTargetNode then //移動到本身父節點不容許移動
begin
HintBar.Panels[0].Text := '不容許移動到本身的父節點';
Result := True;
Break;
end;
end;
end;
// //事件內部函數4.判斷目標(父、子)節點中是否與選中節點名稱相同
function IsExistSelectObject(selectedList: TVNodeArray): Boolean;
var
dstNode : PVirtualNode;
n : PVirtualNode;
i : Integer;
TargetChildNode : PVirtualNode;
TargetParentNode : PVirtualNode;
SelectNodeName : String;
TargetNodeName : String;
TargetChildNodeName : String;
TargetParentNodeName: String;
SelectNodeLevel : Integer;
TargetNodeLevel : Integer;
begin
Result := False;
if Length(selectedList) = 0 then
begin
Exit;
end;
dstNode := Sender.DropTargetNode;
TargetChildNode := dstNode.FirstChild;
TargetParentNode := dstNode.Parent;
TargetNodeName := pjdtransline(VtPurview.GetNodeData(dstNode)^).name;
TargetNodeLevel := pjdtransline(VtPurview.GetNodeData(dstNode)^).LevelID;
for i := 0 to High(selectedList) do
begin
n := selectedList[i];
SelectNodeName := pjdtransline(VtPurview.GetNodeData(n)^).name;
SelectNodeLevel := pjdtransline(VtPurview.GetNodeData(n)^).LevelID;
if (TargetNodeLevel > SelectNodeLevel) then //目標節點級別不能比選中節點級別低
begin
HintBar.Panels[0].Text := '目標節點級別比選中節點級別低,不能移動!';
Result := True;
Break;
end;
if (TargetNodeName = SelectNodeName) then //目標節點與選中節點相同
begin
HintBar.Panels[0].Text := '目標節點值與選中節點值相同,不能移動!';
Result := True;
Break;
end;
while TargetChildNode <> nil do
begin
TargetChildNodeName := pjdtransline(VtPurview.GetNodeData(TargetChildNode)^).name;
if TargetChildNodeName = SelectNodeName then //目標子節點與選中節點相同
begin
HintBar.Panels[0].Text := '目標子節點存在與選中節點值相同的節點,不能移動!';
Result := True;
Break;
end;
TargetChildNode := TargetChildNode.NextSibling;
end;
end;
end;
// //事件內部函數6.判斷是否移動本身子節點或子子節點
function IsAncestor(vnDescendant, vnAncestor: PVirtualNode): Boolean;
var
p: PVirtualNode;
begin
Result := False;
p := vnDescendant.Parent;
while p <> nil do
begin
if p = vnAncestor then
begin
HintBar.Panels[0].Text := '不能移動到本身的子節點或子子節點';
Result := True;
Exit;
end;
p := p.Parent;
end;
end;
//事件定義變量
var
Node : TTreeNode;
VirtualStringTree1: TVirtualStringTree;
dstNode, srcNode: PVirtualNode;
srcText, dstText, s: string;
selectedList: TVNodeArray;
i: Integer;
begin
Accept := False;
if not (Source is TVirtualStringTree) then Exit;
VirtualStringTree1 := TVirtualStringTree(Source);
dstNode := Sender.DropTargetNode;
srcNode := VirtualStringTree1.FocusedNode;
if (srcNode = nil) or (dstNode = nil) then Exit;
if srcNode = dstNode then
begin
HintBar.Panels[0].Text := '目標節點必須與選中節點不一樣!';
Exit;
end;
selectedList := GetSelectedVNodes(VirtualStringTree1);
if IsSameLevel(selectedList) then
begin
Accept := False;
Exit;
end;
if IsExistSelectObject(selectedList) then
begin
Accept := False;
Exit;
end;
// dstText := GetVNodeData(dstNode, VirtualStringTree1).Name;
case Mode of
dmAbove: // 成爲父節點;
begin
Accept := False;
end;
dmBelow: // 成爲子節點,本例主要採用成爲子節點模式
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
Accept := not IsAncestor(dstNode, srcNode);
if not Accept then Break;
end;
end;
dmOnNode: // 成爲同級節點
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
Accept := not IsAncestor(dstNode, srcNode);
if Accept then
HintBar.Panels[0].Text := '能夠移動'
else
Break;
end;
end;
dmNowhere:
Accept := False;
else
end;
end;
2、DragDrop事件
procedure Tform1.VirtualStringTree1DragDrop(
Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
Formats: TFormatArray; Shift: TShiftState; Pt: TPoint;
var Effect: Integer; Mode: TDropMode);
//事件內部函數--獲取選中節點的list
function GetSelectedVNodes(VtPurview: TVirtualStringTree): TVNodeArray;
var
list: TList;
n: PVirtualNode;
i: Integer;
begin
list := TList.Create;
n := VtPurview.GetFirstSelected;
while n <> nil do
begin
list.Add(n);
n := VtPurview.GetNextSelected(n);
end;
SetLength(Result, list.Count);
for i := 0 to list.Count-1 do
begin
Result[i] := list[i];
end;
list.Free;
end;
var
VirtualStringTree1: TVirtualStringTree;
dstNode, srcNode: PVirtualNode;
selectedList: TVNodeArray;
i: Integer;
TargetNodeID : integer;
SelectNodeID : integer;
SelectNodeFID: integer;
sql_str : string;
begin
VirtualStringTree1 := TVirtualStringTree(Source);
dstNode := Sender.DropTargetNode;
TargetNodeID := PPurview(VtPurview.GetNodeData(dstNode)^).ID;
selectedList := GetSelectedVNodes(VirtualStringTree1);
srcNode := VirtualStringTree1.FocusedNode;
if (srcNode = nil) or (dstNode = nil) then Exit;
case Mode of
dmAbove: // 成爲父節點;
begin
end;
dmBelow: // 成爲子節點
begin
if IDYES = MessageBox(Handle, PChar('是否將操做保存到數據庫?'), '確認保存',MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON2) then
begin
for i := 0 to High(selectedList) do
begin
srcNode := selectedList[i];
VirtualStringTree1.MoveTo(srcNode, dstNode, amAddChildFirst, False);
SelectNodeID := PPurview(VtPurview.GetNodeData(srcNode)^).ID;
SelectNodeFID := PPurview(VtPurview.GetNodeData(srcNode)^).FatherID;
//執行數據庫操做
if sql_str = '' then
sql_str := Format('exec p_VehicleGroupTreeDragMove %d,%d,%d ',
[SelectNodeID,
SelectNodeFID,
TargetNodeID
])
else
sql_str := sql_str + Format(';exec p_VehicleGroupTreeDragMove %d,%d,%d ',
[SelectNodeID,
SelectNodeFID,
TargetNodeID
]);
end;
VirtualStringTree1.Sort(dstNode, 0, sdAscending, False);
end
else
exit;
end;
dmOnNode: // 成爲同級節點
begin
end;
dmNowhere:
begin
end;
else
end;
if sql_str<>'' then
begin
ExcuteSQL(sql_str); //保存拖動後節點的上下級關係
end;
end;
-------------------------------------------------VirtualStringTree樹拖動操做實現結束-------------------------------------------------------------------------
6、實現VirtualStringTree(TVirtualStringTree)樹節點字體顏色分多顏色顯示 oncellpaint()事件
客戶要求盲區或掉線的字體要顯示紅色,速度值要顯示灰色
代碼以下:
procedure TfrmMain.vtActiveVehiclePaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType);
begin
p_node_data := TGPSClientVTVUtils.ExtractActiveVehicleNodeData(vtActiveVehicle, Node); //獲取節點data
if not Assigned(p_node_data) then
Exit;
vInfo := PGPSClientVehicleInfoColumn(vtActiveVehicle.Header.Columns[Column].Data);
if vInfo <> nil then
begin
if (Pos('盲區',p_node_data^.CarInfo.GpsInfo.GpsState)>0) and //判斷節點值知足某條件
(vInfo^.FieldInfo.FieldName = 'GPS_Speed') then //判斷是哪一個列,若是是整個節點都變顏色可不需此條件
TargetCanvas.Font.Color := clMedGray; //速度列變灰色
if (Pos('盲區',p_node_data^.CarInfo.GpsInfo.GpsState)>0) and
(vInfo^.FieldInfo.FieldName = 'GPS_Precision') then
TargetCanvas.Font.Color := clred; //精度列變紅色
if (SecondsBetween(Now(), p_node_data^.CarInfo.GpsInfo.GPSTime)>=7200) and //盲區條件
(vInfo^.FieldInfo.FieldName = 'GPS_Speed') then //速度列
TargetCanvas.Font.Color := clMedGray; if (SecondsBetween(Now(), p_node_data^.CarInfo.GpsInfo.GPSTime)>=7200) and (vInfo^.FieldInfo.FieldName = 'GPS_RealStatus') then TargetCanvas.Font.Color := clred; end;