zoukankan      html  css  js  c++  java
  • delphi中VirtualStringTree树使用方法之终结篇!

    VirtualStringTree 的用法详解:
    作者:张志宝go淘宝

    例子:创建了一个树名为VirtualStringTree1,第一列显示数据库字段ID的值,标题为编号;第二列显示字段Name的值,标题为名字。
    一、【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也就是在第一列前面

          并设置ongettext()事件和onInitailNode()事件,见下面事件部分。

    --------------------------------------------------------------------------------------------------------------------------------------------

    二、 【TVirtualStringTree常用方法 】 
        VirtualStringTree1.NodeDataSize := sizeOf(TMyNodeData);  //设置占存储空间大小

       树节点选中: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

    ---------------------------------------------------------------------------------------------------------------------------

    三、【TVirtualStringTree显示数据库字段内容】:

    //定义一个指针

    type

      Tjdtransline =record

           id: integer;     //编号

          name : string;  //名称

           levelID : integer;//级别,例如总公司levelID 为0、二级公司为1、三级公司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;

    ------------------------------------------------------------------------------------------------------------------------------------

    四、 【TVirtualStringTree设置节点展开与折叠的图标 】 
      OnInitNode()  //设置结点的节点是否有子节点类型(‘+’、‘—’显示)

      begin
      Include(InitialStates, ivsHasChildren);
      Node.CheckType := ctTriStateCheckBox;

      end;

    -------------------------------------------------VirtualStringTree树拖动操作实现开始-------------------------------------------------------------------------

    五、【VirtualStringTree树节点拖动实现】

    主要设置其DragOver和DragDrop事件。其中DragOver控制是否允许移动;DragDrop控制移动后执行的操作。

    //一、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;

    二、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树拖动操作实现结束-------------------------------------------------------------------------

    六、实现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;

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    终于总结完了,希望对大家有所帮助,欢迎提出宝贵意见,以便改进!

  • 相关阅读:
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现业务
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 开发流程
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 报表系统集成说明
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 处理报表
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据访问
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 分布式应用
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现插件
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 对象设计器使用帮助
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据层开发
    Jquery 中的CheckBox、 RadioButton、 DropDownList、CheckBoxList、RadioButtonList的取值赋值
  • 原文地址:https://www.cnblogs.com/rogge7/p/4609220.html
Copyright © 2011-2022 走看看