我想扩展树型控件节点数据类型的功能,
主要是添加一个属性如Checked(True,False);
用来标识改节点已经被用户做了一个选择标志。有很多这样类似的控件功能扩展,主要是如何修改
Items一类的数据,如:TreeView.Items
ListBox.Items
等等,然后在构造出相应的高级控件,TreeView,ListBox等。

解决方案 »

  1.   

    用他的data来扩展吧,比扩展类可能容易些。
      

  2.   

    我觉得应该扩展TTreeNode
    treenode内容如下
    -------------------------------
      TTreeNode = class(TPersistent)
      private
        FOwner: TTreeNodes;
        FText: string;
        FData: Pointer;
        FItemId: HTreeItem;
        FImageIndex: TImageIndex;
        FSelectedIndex: Integer;
        FOverlayIndex: Integer;
        FStateIndex: Integer;
        FDeleting: Boolean;
        FInTree: Boolean;
        function CompareCount(CompareMe: Integer): Boolean;
        function DoCanExpand(Expand: Boolean): Boolean;
        procedure DoExpand(Expand: Boolean);
        procedure ExpandItem(Expand: Boolean; Recurse: Boolean);
        function GetAbsoluteIndex: Integer;
        function GetExpanded: Boolean;
        function GetLevel: Integer;
        function GetParent: TTreeNode;
        function GetChildren: Boolean;
        function GetCut: Boolean;
        function GetDropTarget: Boolean;
        function GetFocused: Boolean;
        function GetIndex: Integer;
        function GetItem(Index: Integer): TTreeNode;
        function GetSelected: Boolean;
        function GetCount: Integer;
        function GetTreeView: TCustomTreeView;
        procedure InternalMove(ParentNode, Node: TTreeNode; HItem: HTreeItem;
          AddMode: TAddMode);
        function IsEqual(Node: TTreeNode): Boolean;
        function IsNodeVisible: Boolean;
        procedure ReadData(Stream: TStream; Info: PNodeInfo);
        procedure SetChildren(Value: Boolean);
        procedure SetCut(Value: Boolean);
        procedure SetData(Value: Pointer);
        procedure SetDropTarget(Value: Boolean);
        procedure SetItem(Index: Integer; Value: TTreeNode);
        procedure SetExpanded(Value: Boolean);
        procedure SetFocused(Value: Boolean);
        procedure SetImageIndex(Value: TImageIndex);
        procedure SetOverlayIndex(Value: Integer);
        procedure SetSelectedIndex(Value: Integer);
        procedure SetSelected(Value: Boolean);
        procedure SetStateIndex(Value: Integer);
        procedure SetText(const S: string);
        procedure WriteData(Stream: TStream; Info: PNodeInfo);
      protected
        function GetState(NodeState: TNodeState): Boolean;
        procedure SetState(NodeState: TNodeState; Value: Boolean);
        procedure SetSelectedBit(Value: Boolean);
      public
        constructor Create(AOwner: TTreeNodes);
        destructor Destroy; override;
        function AlphaSort(ARecurse: Boolean = False): Boolean;
        procedure Assign(Source: TPersistent); override;
        procedure Collapse(Recurse: Boolean);
        function CustomSort(SortProc: TTVCompare; Data: Longint; ARecurse: Boolean = False): Boolean;
        procedure Delete;
        procedure DeleteChildren;
        function DisplayRect(TextOnly: Boolean): TRect;
        function EditText: Boolean;
        procedure EndEdit(Cancel: Boolean);
        procedure Expand(Recurse: Boolean);
        function getFirstChild: TTreeNode; {GetFirstChild conflicts with C++ macro}
        function GetHandle: HWND;
        function GetLastChild: TTreeNode;
        function GetNext: TTreeNode;
        function GetNextChild(Value: TTreeNode): TTreeNode;
        function getNextSibling: TTreeNode; {GetNextSibling conflicts with C++ macro}
        function GetNextVisible: TTreeNode;
        function GetPrev: TTreeNode;
        function GetPrevChild(Value: TTreeNode): TTreeNode;
        function getPrevSibling: TTreeNode; {GetPrevSibling conflicts with a C++ macro}
        function GetPrevVisible: TTreeNode;
        function HasAsParent(Value: TTreeNode): Boolean;
        function IndexOf(Value: TTreeNode): Integer;
        procedure MakeVisible;
        procedure MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode); virtual;
        property AbsoluteIndex: Integer read GetAbsoluteIndex;
        function IsFirstNode: Boolean;
        property Count: Integer read GetCount;
        property Cut: Boolean read GetCut write SetCut;
        property Data: Pointer read FData write SetData;
        property Deleting: Boolean read FDeleting;
        property Focused: Boolean read GetFocused write SetFocused;
        property DropTarget: Boolean read GetDropTarget write SetDropTarget;
        property Selected: Boolean read GetSelected write SetSelected;
        property Expanded: Boolean read GetExpanded write SetExpanded;
        property Handle: HWND read GetHandle;
        property HasChildren: Boolean read GetChildren write SetChildren;
        property ImageIndex: TImageIndex read FImageIndex write SetImageIndex;
        property Index: Integer read GetIndex;
        property IsVisible: Boolean read IsNodeVisible;
        property Item[Index: Integer]: TTreeNode read GetItem write SetItem; default;
        property ItemId: HTreeItem read FItemId;
        property Level: Integer read GetLevel;
        property OverlayIndex: Integer read FOverlayIndex write SetOverlayIndex;
        property Owner: TTreeNodes read FOwner;
        property Parent: TTreeNode read GetParent;
        property SelectedIndex: Integer read FSelectedIndex write SetSelectedIndex;
        property StateIndex: Integer read FStateIndex write SetStateIndex;
        property Text: string read FText write SetText;
        property TreeView: TCustomTreeView read GetTreeView;
      end;
      

  3.   

    Checked(True,False);
    -------------------------
    这个如果转换成selected就很方便了
    系统已经完成
      

  4.   

    转化成selected不行,我的树可能会有多选。
    我的树型控件已经扩展了,其效果就好像金山杀毒软件中的目录选择树型控件一样
    是有一个选择构选框的,可以有多个节点被选中。
    所以就需要有一个Checked属性来检测某个节点是否被构选了。
      

  5.   

    那是不是要把TreeNode和TreeView都重新写一扁啊
      

  6.   

    嗯,有些控件是这样实现的TreeView有Images属性不是吗?自己做三张小图片:全选中、部分选中、不选状态(直接拍下CheckBox三种状态的图片在加工一下就可以了),然后在点击事件中根据具体情况设置TTreeNodes的ImageIndex就OK了。我也是这么实现的,挺好用的
      

  7.   

    //参考如下代码~~
    uses CommCtrl;function TreeNodeGetChecked(mTreeNode: TTreeNode): Boolean;
    var
      vTVItem: TTVItem;
    begin
      Result := False;
      if not Assigned(mTreeNode) or not Assigned(mTreeNode.TreeView) then Exit;
      vTVItem.mask := TVIF_STATE;
      vTVItem.hItem := mTreeNode.ItemId;
      if TreeView_GetItem(mTreeNode.TreeView.Handle, vTVItem) then
        Result := (vTVItem.State and IndexToStateImageMask(2)) > 0; //0: None 1: False 2: True
    end; { TreeNodeGetChecked }function TreeNodeSetChecked(mTreeNode: TTreeNode; mChecked: Boolean): Boolean;
    var
      vTVItem: TTVItem;
    begin
      Result := False;
      if not Assigned(mTreeNode) or not Assigned(mTreeNode.TreeView) then Exit;  vTVItem.mask := TVIF_STATE;
      vTVItem.hItem := mTreeNode.ItemId;
      TreeView_GetItem(mTreeNode.TreeView.Handle, vTVItem);
      if not TreeView_GetItem(mTreeNode.TreeView.Handle, vTVItem) then Exit;
      vTVItem.stateMask := TVIS_STATEIMAGEMASK;
      vTVItem.state := IndexToStateImageMask(Succ(Ord(mChecked)));
      Result := TreeView_SetItem(mTreeNode.TreeView.Handle, vTVItem);
    end; { TreeNodeSetChecked }procedure TForm1.FormCreate(Sender: TObject);
    begin
      SetWindowLong(TreeView1.Handle, GWL_STYLE,
        GetWindowLong(TreeView1.Handle, GWL_STYLE) or TVS_CHECKBOXES);
    end;procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
      procedure pSelect(mTreeNode: TTreeNode; mChecked: Boolean);
      var
        I: Integer;
      begin
        TreeNodeSetChecked(mTreeNode, mChecked);
        for I := 0 to mTreeNode.Count - 1 do pSelect(mTreeNode[I], mChecked);
      end;  procedure pSelectYes(mTreeNode: TTreeNode);
      begin
        while Assigned(mTreeNode.Parent) and
          not TreeNodeGetChecked(mTreeNode.Parent) do begin
          TreeNodeSetChecked(mTreeNode.Parent, True);
          mTreeNode := mTreeNode.Parent;
        end;
      end;  procedure pSelectNo(mTreeNode: TTreeNode);
      var
        I: Integer;
      begin
        if Assigned(mTreeNode.Parent) and TreeNodeGetChecked(mTreeNode.Parent) then begin
          for I := 0 to mTreeNode.Parent.Count - 1 do
            if TreeNodeGetChecked(mTreeNode.Parent[I]) then Exit;
          TreeNodeSetChecked(mTreeNode.Parent, False);
          pSelectNo(mTreeNode.Parent);
        end;
      end;var
      vTreeNode: TTreeNode;
    begin
      if not (htOnStateIcon in TTreeView(Sender).GetHitTestInfoAt(X, Y)) then Exit;
      vTreeNode := TTreeView(Sender).GetNodeAt(X, Y);
      pSelect(vTreeNode, TreeNodeGetChecked(vTreeNode));
      if not TreeNodeGetChecked(vTreeNode) then
        pSelectNo(vTreeNode)
      else pSelectYes(vTreeNode);
    end;function TreeNodeSetValue(mTreeNode: TTreeNode; mValue: Integer): Boolean;
    var
      vTVItem: TTVItem;
    begin
      Result := False;
      if not Assigned(mTreeNode) or not Assigned(mTreeNode.TreeView) then Exit;  vTVItem.mask := TVIF_STATE;
      vTVItem.hItem := mTreeNode.ItemId;
      TreeView_GetItem(mTreeNode.TreeView.Handle, vTVItem);
      if not TreeView_GetItem(mTreeNode.TreeView.Handle, vTVItem) then Exit;
      vTVItem.stateMask := TVIS_STATEIMAGEMASK;
      vTVItem.state := IndexToStateImageMask(mValue);
      Result := TreeView_SetItem(mTreeNode.TreeView.Handle, vTVItem);
    end; { TreeNodeSetChecked }
      

  8.   

    TO yu98041154(凋花溅泪) 
       我的实现原理差不多是这样的,但是我需要每个节点要有一个Checked属性啊,兄弟。TO zswang(伴水清清)(专家门诊清洁工)
       好像你的代码有一定的道理,我去研究一下。呵呵,谢谢各位的支持,希望再接再厉,共同进步。
      

  9.   

    TO zswang(伴水清清)(专家门诊清洁工)
      TVS_CHECKBOXES:是一个什么东西,是系统常量还是自定义的常量.你能不能把你上面的所  有代码都发给我看看。
       [email protected]
      

  10.   

    http://www.xiya.com.cn/xiangqin/awind/codes/treechk.rar你看一下,以前写的一个模拟CheckBox例子,没法封装成控件,实现方法和yu98041154(凋花溅泪) 的一样
      

  11.   

    再发问:  对于上面的问题,我重新写了树的组件,但是遇到了一个新问题,树的Items属性的编辑器没有了。
    请问怎样才能把属性编辑器也一起继承过来啊。