VirtualStringTree 的用法詳解: 做者:張志寶go淘寶數據庫 例子:建立了一個樹名爲VirtualStringTree1,第一列顯示數據庫字段ID的值,標題爲編號;第二列顯示字段Name的值,標題爲名字。 1、【TVirtualStringTree經常使用屬性】 BorderStyle :設置邊框選項 bsSingle設置單邊框 爲TVirtualStringTree添加列及列標題: Header--Columns : 設置列 點擊「…」,在彈出界面點擊add new按鈕,就增長一列,在其text中輸入列名,在width輸入列寬度; Header--options-hovisible: 設置列可顯示!! 函數 Header-Style :設置樹的主題類型 ScrollBaroptions--AlwaysVisible 滾動條是否老是可見 ScrollBarOptions-ScrollBars-ssVertical 設置爲只有豎向滾動條 爲TVirtualStringTree添加勾選框、選擇框、複選框: TreeOptions----MiscOpitions---toCheckSupport 設置爲True便可 CheckImageKind 爲勾選框設置圖標字體 Header-Maincolumn 設置勾選框在第幾列前面,默認爲0也就是在第一列前面spa 並設置ongettext()事件和onInitailNode()事件,見下面事件部分。指針 --------------------------------------------------------------------------------------------------------------------------------------------orm 2、 【TVirtualStringTree經常使用方法 】 VirtualStringTree1.NodeDataSize := sizeOf(TMyNodeData); //設置佔存儲空間大小htm 樹節點選中:VirtualStringTree1.Selected[p_node]True; //設置節點p_node處於選中狀態 樹節點勾選框選中:p_node.CheckState:=cscheckedNormal;//設置節點p_node處於勾選狀態 onchecked()事件:設置節點勾選時觸發的事件,其中第二個參數就是勾選的節點 取消選中的節點:VirtualStringTree1.ClearSelection; 樹節點刪除: 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; ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 終於總結完了,但願對你們有所幫助,歡迎提出寶貴意見,以便改進! |