这是我在2000年写的程序,直到现在我还认为是比较精品的
以下全部代码实现了一个树类
TMyList是在delphi的TList基础上改造的,加入了批量删除
TNode是节点类
TNodes是对节点类的封装,实现了一棵树的增、删、改、查等操作
以下是TMyList的源代码unit List;
//改造自delphi的TList,增加了批量删除
interfaceuses
  Classes, RTLConsts;type
  TMyList = class(TObject)
  private
    FList: PPointerList;
    FCount: Integer;
    FCapacity: Integer;
  protected
    function Get(Index: Integer): Pointer;
    procedure Grow;
    procedure Put(Index: Integer; Item: Pointer);
    procedure SetCapacity(NewCapacity: Integer);
  public
    destructor Destroy; override;
    function Add(Item: Pointer): Integer;
    procedure Clear;
    procedure Delete(Index: Integer; ItemCount: Integer = 1);
    class procedure Error(const Msg: string; Data: Integer); overload;
    class procedure Error(Msg: PResStringRec; Data: Integer); overload;
    procedure Exchange(Index1, Index2: Integer);
    function First: Pointer;
    function IndexOf(Item: Pointer): Integer;
    procedure Insert(Index: Integer; Item: Pointer);
    function Last: Pointer;
    property Capacity: Integer read FCapacity write SetCapacity;
    property Count: Integer read FCount;
    property Items[Index: Integer]: Pointer read Get write Put; default;
  end;implementationuses
  Consts;{ TMyList }destructor TMyList.Destroy;
begin
  Clear;
end;function TMyList.Add(Item: Pointer): Integer;
begin
  Result := FCount;
  if Result = FCapacity then
    Grow;
  FList^[Result] := Item;
  Inc(FCount);
end;procedure TMyList.Clear;
begin
  FCount := 0;
  SetCapacity(0);
end;class procedure TMyList.Error(const Msg: string; Data: Integer);  function ReturnAddr: Pointer;
  asm
          MOV     EAX,[EBP+4]
  end;begin
  raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr;
end;class procedure TMyList.Error(Msg: PResStringRec; Data: Integer);
begin
  TMyList.Error(LoadResString(Msg), Data);
end;procedure TMyList.Exchange(Index1, Index2: Integer);
var
  Item: Pointer;
begin
  if (Index1 < 0) or (Index1 >= FCount) then
    Error(@SListIndexError, Index1);
  if (Index2 < 0) or (Index2 >= FCount) then
    Error(@SListIndexError, Index2);
  Item := FList^[Index1];
  FList^[Index1] := FList^[Index2];
  FList^[Index2] := Item;
end;function TMyList.First: Pointer;
begin
  Result := Get(0);
end;function TMyList.Get(Index: Integer): Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
    Error(@SListIndexError, Index);
  Result := FList^[Index];
end;procedure TMyList.Grow;
var
  Delta: Integer;
begin
  if FCapacity > 64 then
    Delta := FCapacity div 4
  else
    if FCapacity > 8 then
      Delta := 16
    else
      Delta := 4;
  SetCapacity(FCapacity + Delta);
end;function TMyList.IndexOf(Item: Pointer): Integer;
begin
  Result := 0;
  while (Result < FCount) and (FList^[Result] <> Item) do
    Inc(Result);
  if Result = FCount then
    Result := -1;
end;procedure TMyList.Insert(Index: Integer; Item: Pointer);
begin
  if (Index < 0) or (Index > FCount) then
    Error(@SListIndexError, Index);
  if FCount = FCapacity then
    Grow;
  if Index < FCount then
    System.Move(FList^[Index], FList^[Index + 1],
      (FCount - Index) * SizeOf(Pointer));
  FList^[Index] := Item;
  Inc(FCount);
end;function TMyList.Last: Pointer;
begin
  Result := Get(FCount - 1);
end;procedure TMyList.Put(Index: Integer; Item: Pointer);
begin
  if (Index < 0) or (Index >= FCount) then
    Error(@SListIndexError, Index);
  FList^[Index] := Item;
end;procedure TMyList.SetCapacity(NewCapacity: Integer);
begin
  if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
    Error(@SListCapacityError, NewCapacity);
  if NewCapacity <> FCapacity then
  begin
    ReallocMem(FList, NewCapacity * SizeOf(Pointer));
    FCapacity := NewCapacity;
  end;
end;procedure TMyList.Delete(Index: Integer; ItemCount: Integer = 1);
begin
  if (Index < 0) or (Index >= FCount) then
    Error(@SListIndexError, Index);
  if ItemCount > FCount - Index then
    ItemCount := FCount - Index;
  if Index < FCount then
    Move(FList[Index + ItemCount], FList[Index],
         (FCount - (Index + ItemCount)) * SizeOf(Pointer));
  Dec(FCount, ItemCount);
end;end.

解决方案 »

  1.   

    unit Tree;interfaceuses
      List, SysUtils;type
      TNodes = class;
      TNode = class;
      TAddMode = (amAddChildFirst, amAddChild);  TNode = class(TObject)
      private
        FOwner: TNodes;
        FData: Pointer;
        FParent: TNode;
        FFirstChild: TNode;
        FNextSibling: TNode;
        FPrevSibling: TNode;
        FExpanded: Boolean;
        function GetHasChildren: Boolean;
        function GetLevel: Integer;
        function GetParent: TNode;
        function GetLastSibling: TNode;
        function GetFirstSibling: TNode;
        function GetLastChild: TNode;
        function GetIsVisible: Boolean;
        function GetCount: Integer;
      public
        constructor Create(AOwner: TNodes);
        destructor Destroy; override;
        procedure Collapse(Recurse: Boolean);
        procedure Expand(Recurse: Boolean);
        procedure Delete;
        procedure DeleteChildren;
    //    procedure MoveTo(Destination: TNode; Mode: TMoveMode);
        procedure LevelDown;
        procedure LevelUp;
        procedure MoveDown;
        procedure MoveUp;
        property FirstChild: TNode read FFirstChild;
        property NextSibling: TNode read FNextSibling;
        property PrevSibling: TNode read FPrevSibling;
        property Data: Pointer read FData write FData;
        property Expanded: Boolean read FExpanded write FExpanded;
        property HasChildren: Boolean read GetHasChildren;
        property Level: Integer read GetLevel;
        property Owner: TNodes read FOwner;
        property Parent: TNode read GetParent;
        property LastSibling: TNode read GetLastSibling;
        property FirstSibling: TNode read GetFirstSibling;
        property LastChild: TNode read GetLastChild;
        property IsVisible: Boolean read GetIsVisible;
        property Count: Integer read GetCount;
      end;  TNodes = class(TObject)
      private
        FUpdateCount: Integer;
        FRoot: TNode;
        FCount: Integer;
        FNodeList: TMyList;
        FCapacity: Integer;
        FTag: Integer;
        procedure BuildNodeList;
        function InternalAdd(Node: TNode; Ptr: Pointer; AddMode: TAddMode): TNode;
        function GetItems(Index: Integer): TNode;
    //    procedure Move(Source, Destination: TNode; Mode: TMoveMode);
      public
        constructor Create;
        destructor Destroy; override;
        function AddChildFirst(Node: TNode; Ptr: Pointer): TNode;
        function AddChild(Node: TNode; Ptr: Pointer): TNode;
        function AddFirst(Node: TNode; Ptr: Pointer): TNode;
        function Add(Node: TNode; Ptr: Pointer): TNode;
        function InsertObject(Node: TNode; Ptr: Pointer): TNode;
        function IndexOf(Node: TNode): Integer;
        procedure BeginUpdate;
        procedure EndUpdate;
        procedure Clear;
        procedure AdjustDelete(Node: TNode);
        procedure Delete(Node: TNode); overload;
        procedure Delete(Index: Integer); overload;
        procedure DeleteChildren(Node: TNode); overload;
        procedure DeleteChildren(Index: Integer); overload;
        procedure LevelDown(Node: TNode);
        procedure LevelUp(Node: TNode);
        procedure MoveDown(Node: TNode);
        procedure MoveUp(Node: TNode);
        procedure FullExpand;
        procedure FullCollapse;
        property Root: TNode read FRoot;
        property Count: Integer read FCount;
        property Capacity: Integer read FCapacity write FCapacity;
        property Tag: Integer read FTag write FTag;
        property Items[Index: Integer]: TNode read GetItems; default;
      end;//function IsAncestor(Ancestor, Child: TNode): Boolean;implementation{function IsAncestor(Ancestor, Child: TNode): Boolean;
    begin
      Result := False;
      if Child = nil then
        raise Exception.Create('参数Child不能为空');
      if Ancestor = nil then
      begin
        Result := True;
        exit;
      end;
      Child := Child.Parent;
      while Child <> nil do
      begin
        if Child = Ancestor then
        begin
          Result := True;
          exit;
        end;
        Child := Child.Parent;
      end;
    end;}{ TNode }constructor TNode.Create(AOwner: TNodes);
    begin
      inherited Create;
      FOwner := AOwner;
      Inc(FOwner.FCount);
      FExpanded := False;
    end;destructor TNode.Destroy;
    begin
      Dec(FOwner.FCount);
      inherited;
    end;procedure TNode.Collapse(Recurse: Boolean);
    var
      Node: TNode;
    begin
      FExpanded := False;
      if Recurse then
      begin
        Node := FFirstChild;
        while Node <> nil do
        begin
          Node.Collapse(Recurse);
          Node := Node.FNextSibling;
        end;
      end;
    end;procedure TNode.Expand(Recurse: Boolean);
    var
      Node: TNode;
    begin
      FExpanded := True;
      if Recurse then
      begin
        Node := FFirstChild;
        while Node <> nil do
        begin
          Node.Expand(Recurse);
          Node := Node.FNextSibling;
        end;
      end;
    end;procedure TNode.Delete;
    begin
      FOwner.Delete(Self);
    end;procedure TNode.DeleteChildren;
    begin
      FOwner.DeleteChildren(Self);
    end;function TNode.GetHasChildren: Boolean;
    begin
      Result := FFirstChild <> nil;
    end;function TNode.GetLevel: Integer;
    var
      Node: TNode;
    begin
      Result := 0;
      Node := FParent;
      while Node <> nil do
      begin
        Inc(Result);
        Node := Node.FParent;
      end;
    end;function TNode.GetParent: TNode;
    begin
      Result := FParent;
    end;function TNode.GetLastSibling: TNode;
    begin
      Result := Self;
      while Result.FNextSibling <> nil do
        Result := Result.FNextSibling;
    end;function TNode.GetFirstSibling: TNode;
    begin
      Result := Self;
      while Result.FPrevSibling <> nil do
        Result := Result.FPrevSibling;
    end;function TNode.GetLastChild: TNode;
    begin
      Result := FFirstChild;
      if Result = nil then exit;
      while Result.FNextSibling <> nil do
        Result := Result.FNextSibling;
    end;{procedure TNode.MoveTo(Destination: TNode; Mode: TMoveMode);
    begin
      if Destination = Self then exit;
      if (Destination <> nil) and IsAncestor(Self, Destination) then exit;
      // not realilzed
      FOwner.Move(Self, Destination, Mode);
    end;}procedure TNode.LevelDown;
    begin
      FOwner.LevelDown(Self);
    end;procedure TNode.LevelUp;
    begin
      FOwner.LevelUp(Self);
    end;procedure TNode.MoveDown;
    begin
      FOwner.MoveDown(Self);
    end;procedure TNode.MoveUp;
    begin
      FOwner.MoveUp(Self);
    end;function TNode.GetIsVisible: Boolean;
    begin
      Result := (FParent = nil) or FParent.IsVisible and FParent.FExpanded;
    end;function TNode.GetCount: Integer;
    var
      Node: TNode;
    begin
      Result := 0;
      Node := FFirstChild;
      while Node <> nil do
      begin
        Inc(Result, Node.Count + 1);
        Node := Node.FNextSibling;
      end;
    end;{ TNodes }constructor TNodes.Create;
    begin
      FUpdateCount := 0;
      FCount := 0;
      FCapacity := 0;
      FRoot := nil;
      FTag := 0;
      FNodeList := TMyList.Create;
    end;destructor TNodes.Destroy;
    begin
      Clear;
      FNodeList.Free;
      inherited;
    end;function TNodes.AddChild(Node: TNode; Ptr: Pointer): TNode;
    begin
      Result := InternalAdd(Node, Ptr, amAddChild);
    end;function TNodes.AddChildFirst(Node: TNode; Ptr: Pointer): TNode;
    begin
      Result := InternalAdd(Node, Ptr, amAddChildFirst);
    end;procedure TNodes.BeginUpdate;
    begin
      Inc(FUpdateCount);
    end;procedure TNodes.Clear;
    var
      Node, L_NextSibling: TNode;
    begin
      if FRoot = nil then exit;
      BeginUpdate;
      Node := FRoot;
      while Node <> nil do
      begin
        L_NextSibling := Node.NextSibling;
        Delete(Node);
        Node := L_NextSibling;
      end;
      FRoot := nil;
      EndUpdate;
    end;function DoDelete(Node: TNode): Integer;
    var
      L_Node, L_NextSibling: TNode;
    begin
      Result := 0;
      if Node = nil then exit;
      L_Node := Node.FirstChild;
      while L_Node <> nil do
      begin
        L_NextSibling := L_Node.NextSibling;
        Inc(Result, DoDelete(L_Node));
        L_Node := L_NextSibling;
      end;
      Node.Free;
      Inc(Result);
    end;
      
      

  2.   

    续procedure TNodes.AdjustDelete(Node: TNode);
    var
      L_Parent, L_PrevSibling, L_NextSibling: TNode;
    begin
      if Node = nil then exit;
      L_Parent := Node.Parent;
      L_PrevSibling := Node.PrevSibling;
      L_NextSibling := Node.NextSibling;
     
      if L_PrevSibling = nil then // 无兄
      begin
        if L_Parent = nil then // 无兄无父
        begin
          if L_NextSibling = nil then // 无兄无父无弟
            FRoot := nil
          else // 无兄无父有弟
          begin
            FRoot := L_NextSibling;
            FRoot.FPrevSibling := nil;
          end;
        end
        else // 无兄有父
        begin
          if L_NextSibling = nil then // 无兄有父无弟
            L_Parent.FFirstChild := nil
          else // 无兄有父有弟
          begin
            L_Parent.FFirstChild := L_NextSibling;
            L_NextSibling.FPrevSibling := nil;
          end;
        end;
      end
      else // 有兄
      begin
        if L_NextSibling = nil then // 有兄无弟
          L_PrevSibling.FNextSibling := nil
        else // 有兄有弟
        begin
          L_PrevSibling.FNextSibling := L_NextSibling;
          L_NextSibling.FPrevSibling := L_PrevSibling;
        end;
      end;
    end;
     
    procedure TNodes.Delete(Node: TNode);
    begin
      if Node = nil then exit;
      AdjustDelete(Node);
      DoDelete(Node);
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.Delete(Index: Integer);
    var
      Node: TNode;
    begin
      if FUpdateCount > 0 then
        raise Exception.Create('此时无法进行该操作');
      Node := FNodeList[Index];
      if Node = nil then exit;
      AdjustDelete(Node);
      FNodeList.Delete(Index, DoDelete(Node));
    end;
     
    procedure TNodes.DeleteChildren(Node: TNode);
    var
      L_Node, L_NextSibling: TNode;
    begin
      if Node = nil then exit;
      L_Node := Node.FirstChild;
      while L_Node <> nil do
      begin
        L_NextSibling := L_Node.NextSibling;
        DoDelete(L_Node);
        L_Node := L_NextSibling;
      end;
      Node.FFirstChild := nil;
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.DeleteChildren(Index: Integer);
    var
      Node, L_Node, L_NextSibling: TNode;
      DeleteCount: Integer;
    begin
      if FUpdateCount > 0 then
        raise Exception.Create('此时无法进行该操作');
      Node := FNodeList[Index];
      if Node = nil then exit;
      if not Node.HasChildren then exit;
      DeleteCount := 0;
      L_Node := Node.FirstChild;
      while L_Node <> nil do
      begin
        L_NextSibling := L_Node.NextSibling;
        Inc(DeleteCount, DoDelete(L_Node));
        L_Node := L_NextSibling;
      end;
      Node.FFirstChild := nil;
      FNodeList.Delete(Index+1, DeleteCount);
    end;
     
    procedure TNodes.EndUpdate;
    begin
      if FUpdateCount > 0 then Dec(FUpdateCount);
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.BuildNodeList;
      procedure AddOneNode(Node: TNode);
      begin
        while Node <> nil do
        begin
          FNodeList.Add(Node);
          if Node.FirstChild <> nil then
            AddOneNode(Node.FirstChild);
          Node := Node.NextSibling;
        end;
      end;
    begin
      FNodeList.Clear;
      FNodeList.Capacity := FCapacity;
      AddOneNode(FRoot);
    end;
     
    function TNodes.InsertObject(Node: TNode; Ptr: Pointer): TNode;
    var
      L_Node: TNode;
    begin
      if Node = nil then
        Result := InternalAdd(Node, Ptr, amAddChild)
      else
      begin
        if Node.PrevSibling = nil then
          Result := InternalAdd(Node.Parent, Ptr, amAddChildFirst)
        else
        begin
          Result := TNode.Create(Self);
          Result.Data := Ptr;
          Result.FParent := Node.Parent;
          L_Node := Node.PrevSibling;
          L_Node.FNextSibling := Result;
          Result.FPrevSibling := L_Node;
          Result.FNextSibling := Node;
          Node.FPrevSibling := Result;
          if FUpdateCount = 0 then
            FNodeList.Insert(FNodeList.IndexOf(Node), Result);
        end;
      end;
    end;
     
    function TNodes.InternalAdd(Node: TNode; Ptr: Pointer;
      AddMode: TAddMode): TNode;
    var
      L_Node: TNode;
    begin
      Result := TNode.Create(Self);
      Result.Data := Ptr;
      if Node = nil then
      begin
        if FRoot = nil then
        begin
          FRoot := Result;
          if FUpdateCount = 0 then
            FNodeList.Insert(0, Result);
        end
        else
        case AddMode of
          amAddChildFirst:
            begin
              Result.FNextSibling := FRoot;
              FRoot.FPrevSibling := Result;
              FRoot := Result;
              if FUpdateCount = 0 then
                FNodeList.Insert(0, Result);
            end;
          amAddChild:
            begin
              L_Node := FRoot.GetLastSibling;
              L_Node.FNextSibling := Result;
              Result.FPrevSibling := L_Node;
              if FUpdateCount = 0 then
                FNodeList.Add(Result);
            end;
        end;
      end
      else
      begin
        Result.FParent := Node;
        if Node.HasChildren then
        begin
          if AddMode = amAddChildFirst then
          begin
            L_Node := Node.FirstChild;
            Node.FFirstChild := Result;
            Result.FNextSibling := L_Node;
            L_Node.FPrevSibling := Result;
            if FUpdateCount = 0 then
              FNodeList.Insert(FNodeList.IndexOf(L_Node), Result);
          end
          else
          begin
            L_Node := Node.LastChild;
            L_Node.FNextSibling := Result;
            Result.FPrevSibling := L_Node;
            if FUpdateCount = 0 then
            begin
              while L_Node.HasChildren do
                L_Node := L_Node.LastChild;
              FNodeList.Insert(FNodeList.IndexOf(L_Node)+1, Result);
            end;
          end;
        end
        else
        begin
          Node.FFirstChild := Result;
          if FUpdateCount = 0 then
            FNodeList.Insert(FNodeList.IndexOf(Node)+1, Result);
        end;
      end;
    end;
     
    function TNodes.Add(Node: TNode; Ptr: Pointer): TNode;
    begin
      if Node <> nil then Node := Node.Parent;
      Result := InternalAdd(Node, Ptr, amAddChild);
    end;
     
    function TNodes.AddFirst(Node: TNode; Ptr: Pointer): TNode;
    begin
      if Node <> nil then Node := Node.Parent;
      Result := InternalAdd(Node, Ptr, amAddChildFirst);
    end;
     
    function TNodes.GetItems(Index: Integer): TNode;
    begin
      if FUpdateCount > 0 then
        raise Exception.Create('此时无法进行该操作');
      Result := FNodeList[Index];
    end;
     
    function TNodes.IndexOf(Node: TNode): Integer;
    begin
      if FUpdateCount > 0 then
        raise Exception.Create('此时无法进行该操作');
      Result := FNodeList.IndexOf(Node);
    end;
      

  3.   

    续{procedure TNodes.Move(Source, Destination: TNode; Mode: TMoveMode);
    begin
      case Mode of
        mmAdd:
        mmAddFirst:
        mmAddChild:
        mmAddChildFirst:
        mmInsert:
       end;
    end;}
     
    procedure TNodes.LevelDown(Node: TNode);
    var
      Dest: TNode;
    begin
      Dest := Node.PrevSibling;
      if Dest = nil then
        Dest := Node.NextSibling;
      if Dest = nil then exit;
      AdjustDelete(Node);
      Node.FParent := Dest;
      Node.FNextSibling := nil;
      if Dest.HasChildren then
      begin
        Dest := Dest.LastChild;
        Dest.FNextSibling := Node;
        Node.FPrevSibling := Dest;
      end
      else
      begin
        Dest.FFirstChild := Node;
        Node.FPrevSibling := nil;
      end;
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.LevelUp(Node: TNode);
    var
      L_PrevSibling, L_NextSibling: TNode;
    begin
      if Node.Level = 0 then exit;
      L_PrevSibling := Node.Parent;
      L_NextSibling := Node.Parent.NextSibling;
      AdjustDelete(Node);
      Node.FParent := L_PrevSibling.Parent;
      L_PrevSibling.FNextSibling := Node;
      Node.FPrevSibling := L_PrevSibling;
      Node.FNextSibling := L_NextSibling;
      if L_NextSibling <> nil then
        L_NextSibling.FPrevSibling := Node;
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.MoveDown(Node: TNode);
    var
      L_PrevSibling, L_NextSibling: TNode;
    begin
      L_NextSibling := Node.NextSibling;
      if L_NextSibling = nil then exit;
      AdjustDelete(Node);
      L_PrevSibling := L_NextSibling;
      L_NextSibling := L_NextSibling.NextSibling;
      L_PrevSibling.FNextSibling := Node;
      Node.FPrevSibling := L_PrevSibling;
      Node.FNextSibling := L_NextSibling;
      if L_NextSibling <> nil then
        L_NextSibling.FPrevSibling := Node;
      if FUpdateCount = 0 then BuildNodeList;
    end;
     
    procedure TNodes.MoveUp(Node: TNode);
    var
      L_PrevSibling: TNode;
    begin
      L_PrevSibling := Node.PrevSibling;
      if L_PrevSibling = nil then exit;
      MoveDown(L_PrevSibling);
    end;
     
    procedure TNodes.FullCollapse;
    var
      Node: TNode;
    begin
      Node := FRoot;
      while Node <> nil do
      begin
        Node.Collapse(True);
        Node := Node.NextSibling;
      end;
    end;
     
    procedure TNodes.FullExpand;
    var
      Node: TNode;
    begin
      Node := FRoot;
      while Node <> nil do
      begin
        Node.Expand(True);
        Node := Node.NextSibling;
      end;
    end;
     
    end.
      
      

  4.   

    这段程序不是控件,只是一个类!
    3年前的程序了,现在看到还是感觉很亲切。
    说明:如果程序中不需要按index访问,可以不用TMyList,并将程序中涉及到该list的地方重新改造一下。因为这个list对访问进行了限制,不是随时都可以的。
      

  5.   

    程序员有哪个没有学过数据结构呢?
    可写出来的程序还是有很大差别这段程序用在了国内某建筑软件公司的概预算软件中。
    然后我把StringGrid又改造了一下(说是改造,跟自己写一个差不多,而且代码多了3、4千行),大大增强了原有的功能。
    最后我写了个控件,封装了TNodes、改造后的StringGrid(本身也是个控件)、数据集,做成了个树形网格编辑控件。
    我离开了这家公司后,该公司将我写的控件做成了activex控件,用在了很多产品中。
    涉及到知识产权问题,改造后的StringGrid与树形网格编辑控件我不能共享了,很抱歉!
      

  6.   

    只能email联系,公司内上不了qq
    [email protected]
      

  7.   

    liumengchuan可以用MSN啊。http://messenger.microsoft.com/CN/MSN:[email protected]我是菜鸟,想指导我的请加我。  ^_^我不是程序,因为我没有学过数据结构。目前为公司写一些数据库方面的代码。
      

  8.   

    不会吧,这么狠?连msn也封了??用代理!!:)
      

  9.   

    很需要的就是控制stringgrid的东西。xstringgrid大家用过吗?太难受了,非要焦点移开才能让输入的东西有效。麻烦别考虑版权的问题吧