delphi 容器类 3. TCollection

来源:岁月联盟 编辑:exp 时间:2012-10-16

TCollection 是TCollectionItenm对象一个容器。


  类关系TObject→TPersistent


  每一个TCollection都拥有一组TCollectionItem对象。

  在其Items属性数组中,TCcllection保存集合项目一个下标。Count 属性包含了集合项目数量。
   使用Add和Clear方法可以向集合中加入项目和从集合中删除项目。

 

  从TCollection继承对象能够包含从TCollectionItem继承对象。
例如,一个TDBGridColumns对象包含TColumn对象,这两个类被TDBGrid对象用于表示网格。
下表列出了每一个TCollection对象子类与相应TCollectionltem对象子类以及使用控制组件。
其中,TQuryTableProducer和TWehDispetcher使用控件继承自TWinContril对象。


  TCollection子类 TCollectionItem子类 控件组件


  TCheckConstraints TCheckConstraint 使用Tfield对象控件

 

  TCookieCollection TCookie HTTP响应对象

  TCoolBands TCoolBand TCoolBar

  TDBGridColumns TColumn TDBGrid

  TDependencies TDependency TService


  TDisplayDims TDisplayDim TDecisionGrid


  TFieldDefs TfieldDef TDatsSet 字串6

  THeaderSections THeaderSection THeaderControl 字串4

  TIndexDefs TIndexDef TTable

 

  THTMLTableColumns THTMLTableColumn TQueryTableProducer


  TListColumns TListColumn TListView


  TSuatusPanels TSuatuspanel TStatusBar

 

  TWebActionItems TwebActionitem TwebDispatcher

  使用TCollection和TCollectionitem子类控件,都有一个拥有一个集合5公开属性(
例如,TStatusBarPanels属性拥有一个TStatusPanels)。一个标准属性编辑器,从种属上说被认为是集合编辑器,
它被授引自Object Inspector,以编辑集合中项目。

 


  属性列表

  Count 返回集合中项目数量

  ItemClass 表示集合项目有种类


  Items 提供对集合中项目变址访问

 

  方法列表

  ~TCollection 删除集合及其内每一项目

  Add 创建一新对象实例并加 入到Items属性数组中


  Assign 将另一集合有内容复制到执行该方法对象中

  Bcginupdate 使屏幕更新暂停

  Clear 从集合中删除所有项目

  EndUpdate 使屏幕能够重新进行更新


  FindItemID 返回ID参数指定项目


  Insert 创建TCollectionItem对象并加入到Items属性数组中


  TCollection 创建并初始化一个集合 字串9

 

  属性

  TCollection::Count


  用于返回集合中项目数量。

 

  __property int Count = {read=getCount,nodefanlt};

 

  Count属性包含了Items属性数组中项目数量。因为Items属性数组下标从0开始,因此,Count属性数值总是比Items属性数组最后一个成员下标大1。 字串9

  TCollection::ItemClass

  表示集合项目类。

 


  __property int count = {read =GetXount,nodefauit};

 

  ItemClass返回属于集合项目类(继承自TColliectionItem对象)。
例如,在TCollection对象THeaderSections子类有一个实例中,IetmClass属性返回THeaderSection .


  TCollection::Items

  提供对集合中项目变址访问。

 

  __property TCollectionItem*irems{int Index}={read =GetItem,write=SetItem};


  使用Items属性可以访问集合中单个项目。Index参数数值对应于TCollectionItem对象Index属性。它表示项目 在集合中有位置。 字串2

  方法

  TCollection::~TCollection


  删除集合及其内每一个项目 。

 

  __fastcall virtual~TCollection(void);

 

  不要直接调用~TCollection 用delete会自动调用~TCollection

 

  ~TCollection调用Clear方法,释放在Items属性数组中每一个被子引用项目,然后删除集合本身。

  TCollection::Add

 


  创建一个新TCollectionItem对象实例,并将其加入到Items属性数组中。

 


  TCollectionItem* __fasteall Add(void);


  调用Add可以在集合中创建一个项目。新项目被放置在Items属性数组结尾处。Add返回新集合项目。

  TCollection::Assign

  将另一个集合内容复制到执行该方法对象。

  virtual void __fastcall Assign (TPersistemt*Source);

 


  使用Assign,可以将一个TCollection对象实例内容复制至另一个TCollection对象。Assign方法删除目集合(即执行该方法对象)中所有项目,然后加入由Source参数指定集合Items属性数组中每一个项目复制。

 


  TCollection::BeginUpdate

  使屏幕更新暂停。

  void __fastcall BeginUpdate(void);

 


  BeginUpdate使屏幕更新暂停,直至调用了EndUpdate方法。使用BeginUpdate可以加速进行处理,并且当向一个集合中加入项目或从一个集合中删除项目时,可以避免闪烁。 字串3

  TCollection::EndUpdate

  从集合中删除所有项目。

  void __fastcall CIear(void);

 

  CIear清空Items属性数组并删除每一个TCollectionItem对象。

  TCollection::EndUpdate

  使屏幕能够重新进行更新。

  void __fastcall EndUpdate(void);

  使用EndUpdate,可以使以BeginUpdate方法关闭屏幕能够重新进行更新。

 

  TCollection::FindItemID

 

  返回ID参数指定项目。 字串1

  TCollectionItem* __fastcall FindItemID(int ID);

 


  FindItemID方法返回集合中项目,该项目ID属性被作为一个参数传递。如果没有ID参数指定项目,则FindItemID返回NULL.

字串8


  TCollection::Insert 字串6

  创建一个新TCollectionItem对象实例,并将其加入到Items属性数组中。 字串6

  TCollectionItem* __fastcall Insert(int Index);

字串7

  调用 Insert,可以在集合中一个指定位置处加入一个新项目。在Items属性数组中已经存在从指定位置开始项目将向上移动。Insert返回新集合项目。 字串4

  TColletion::TCollection 字串6

  创建并初始化一个集合。 字串3

  __fastcall TCollection (Sysem::TMetaCIass*ItemCIass);

字串5

  不要直接调用 TCollection。用new会返回新集合一个间接引用。

字串6


  TCollection方法取一个TCollectionItem子类名作为一个参数。该参数确定了由Add方法创建项目类。 字串2

 

====================================================================================

 

TCollection类

  前面我们提到了Delphi的IDE能够自动将字符串列表保存在DFM文件中,并能在运行时将设计期编辑的字符串列表加载进内存(也就是我们通常所说的类的可持续性)。TStrings这种特性比较适合于保存一个对象同多个字符串数据之间关联,比较类似于现实生活中一个人同多个Email账户地址之间的关系。但是,TStrings类型的属性有一个很大的局限那就是,它只能用于设计时保存简单的字符串列表,而不能保存复杂对象列表。而一个父对象同多个子对象之间的聚合关系可能更为常见,比如一列火车可能有好多节车厢构成,每节车厢都有车厢号,车厢类型(卧铺,还是硬座),车厢座位数,车厢服务员名称等属性构成。如果我们想在设计期实现对火车的车厢定制的功能,并能保存车厢的各个属性到窗体文件中,则车厢集合属性定义为TStrings类型的属性是行不通的。

  对于这个问题,Delphi提供了TCollection容器类属性这样一个解决方案。TCollection以及它的容器元素TCollectionItem的接口定义如下:

 TCollection = class(TPersistent)
 …
 protected
  procedure Added(var Item: TCollectionItem); virtual; deprecated;
  procedure Deleting(Item: TCollectionItem); virtual; deprecated;
  property NextID: Integer read FNextID;
  procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); virtual;
  { Design-time editor support }
  function GetAttrCount: Integer; dynamic;
  function GetAttr(Index: Integer): string; dynamic;
  function GetItemAttr(Index, ItemIndex: Integer): string; dynamic;
  procedure Changed;
  function GetItem(Index: Integer): TCollectionItem;
  procedure SetItem(Index: Integer; Value: TCollectionItem);
  procedure SetItemName(Item: TCollectionItem); virtual;
  procedure Update(Item: TCollectionItem); virtual;
  property PropName: string read GetPropName write FPropName;
  property UpdateCount: Integer read FUpdateCount;
 public
  constructor Create(ItemClass: TCollectionItemClass);
  destructor Destroy; override;
  function Owner: TPersistent;
  function Add: TCollectionItem;
  procedure Assign(Source: TPersistent); override;
  procedure BeginUpdate; virtual;
  procedure Clear;
  procedure Delete(Index: Integer);
  procedure EndUpdate; virtual;
  function FindItemID(ID: Integer): TCollectionItem;
  function GetNamePath: string; override;
  function Insert(Index: Integer): TCollectionItem;
  property Count: Integer read GetCount;
  property ItemClass: TCollectionItemClass read FItemClass;
  property Items[Index: Integer]: TCollectionItem read GetItem write SetItem;
 end;
 TCollectionItem = class(TPersistent)

 protected
  procedure Changed(AllItems: Boolean);
  function GetOwner: TPersistent; override;
  function GetDisplayName: string; virtual;
  procedure SetCollection(Value: TCollection); virtual;
  procedure SetIndex(Value: Integer); virtual;
  procedure SetDisplayName(const Value: string); virtual;
 public
  constructor Create(Collection: TCollection); virtual;
  destructor Destroy; override;
  function GetNamePath: string; override;
  property Collection: TCollection read FCollection write SetCollection;
  property ID: Integer read FID;
  property Index: Integer read GetIndex write SetIndex;
  property DisplayName: string read GetDisplayName write SetDisplayName;
 end;

  TCollection类是一个比较复杂特殊的容器类。但是初看上去,它就是一个TCollectionItem对象的容器类,同列表类TList类似,TCollection类也维护一个TCollectionItem对象索引数组,Count属性表示容器中包含的TCollectionItem的数目,同时也提供了Add和Delete方法来添加和删除TCollectionItem对象以及通过下标存取TCollectionItem的属性。看上去和容器类区别不大,但是在VCL内部用于保存和加载组件的TReader和TWriter类提供了两个特殊的方法WriteCollection和ReadCollection用于加载和保存TCollection类型的集合属性。IDE就是通过这两个方法实现对TCollection类型属性的可持续性。

  假设现在需要设计一个火车组件TTrain,TTrain组件有一个TCollection类型的属性Carriages表示多节车厢构成的集合属性,每个车厢则对应于集合属性的元素,从TCollectionItem类继承,有车厢号,车厢类型(卧铺,还是硬座),车厢座位数,车厢服务员名称等属性,下面是我设计的组件的接口:

type
 //车厢类型,硬座、卧铺
 TCarriageType = (ctHard, ctSleeper);
 //车厢类
 TCarriageCollectionItem = class(TCollectionItem)

 published
  //车厢号码
property CarriageNum: Integer read FCarriageNum write FCarriageNum;
//座位数
property SeatCount: Integer read FSeatCount write FSeatCount;
//车厢类型
property CarriageType: TCarriageType read FCarriageType write FCarriageType;
//服务员名称
  property ServerName: string read FServerName write FServerName;
 end;
 TTrain=class;
 //车厢容器属性类 
 TCarriageCollection = class(TCollection)
 private
  FTrain:TTrain;
  function GetItem(Index: Integer): TCarriageCollectionItem;
  procedure SetItem(Index: Integer; const Value: TCarriageCollectionItem);
 protected
  function GetOwner: TPersistent; override;
 public
  constructor Create(ATrain: TTrain);
  function Add: TCarriageCollectionItem;
property Items[Index: Integer]: TCarriageCollectionItem read GetItem
write SetItem; default;
 end;
 //火车类
 TTrain = class(TComponent)
 private
  FItems: TCarriageCollection;
  procedure SetItems(Value: TCarriageCollection);
 public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
 published
  property Carriages: TCarriageCollection read FItems write SetItems;
 end;

  其中车厢类的定义非常简单,只是定义了四个属性。而车厢集合类重定义了静态的Add方法以及Items属性,其返回结果类型改为了TCarriageCollectionItem,下面是车厢集合类的实现代码:

function TCarriageCollection.Add: TCarriageCollectionItem;
begin
 Result:=TCarriageCollectionItem(inherited Add);
end;
  
constructor TCarriageCollection.Create(ATrain: TTrain);
begin
 inherited Create(TCarriageCollectionItem);
 FTrain:=ATrain;
end;
  
function TCarriageCollection.GetItem(
 Index: Integer): TCarriageCollectionItem;
begin
 Result := TCarriageCollectionItem(inherited GetItem(Index));
end;
  
function TCarriageCollection.GetOwner: TPersistent;
begin
 Result:=FTrain;
end;
  
procedure TCarriageCollection.SetItem(Index: Integer;
 const Value: TCarriageCollectionItem);
begin
 inherited SetItem(Index, Value);
end;

  其中Add,GetItem和SetItem都非常简单,就是调用基类的方法,然后将基类的方法的返回结果重新映射为TCollectionItem类型。而构造函数中将TTrain组件作为父组件传入,并重载GetOwner方法,返回TTrain组件,这样处理的原因是IDE会在保存集合属性时调用集合类的GetOwner确认属性的父控件是谁,这样才能把集合属性写到DFM文件中时,才能存放到正确的位置下面,建立正确的聚合关系。

  而火车组件的实现也非常简单,只要定义一个Published Carriages属性就可以了,方法实现代码如下:

constructor TTrain.Create(AOwner: TComponent);
begin
 inherited;
 FItems := TCarriageCollection.Create(Self);
end;
  
destructor TTrain.Destroy;
begin
 FItems.Free;
 inherited;
end;
  
procedure TTrain.SetItems(Value: TCarriageCollection);
begin
 FItems.Assign(Value);
end;

  下面将我们的组件注册到系统面板上之后,就可以在窗体上放上一个TTrain组件,然后然后选中Object Inspector,然后双击Carriages属性,会显示系统默认的集合属性编辑器,使用Add按钮向列表中添加两个车厢,修改一下属性,如下图所示意:

Delphi中的容器类

  从上面的属性编辑器我们,可以看到默认情况下,属性编辑器列表框是按项目索引加上一个横杠来显示车厢的名称,看起来不是很自然。要想修改显示字符串,需要重载TCarriageCollectionItem的GetDisplayName方法。修改后的GetDisplayName方法显示车厢加车厢号码:

function TCarriageCollectionItem.GetDisplayName: string;
begin
 Result:='车厢'+IntToStr(CarriageNum);
end;

  示意图:

 Delphi中的容器类

  保存一下文件,使用View As Text右键菜单命令察看一下DFM文件,我们会看到我们设计的车厢类的属性确实都被写到了DFM文件中,并且Carriages属性的父亲就是Train1:

 object Train1: TTrain
  Carriages = <
   item
    CarriageNum = 1
    SeatCount = 100
    CarriageType = ctHard
    ServerName = '陈省'
   end
   item
    CarriageNum = 2
    SeatCount = 200
    CarriageType = ctHard
    ServerName = 'hubdog'
   end>
  Left = 16
  Top = 8
 End

  TOwnedCollection

  从Delphi4开始,VCL增加了一个TOwnedCollection类,它是TCollection类的子类,如果我们的TCarriageCollection类是从TOwnedCollection类继承的,这时我们就不再需要向上面重载GetOwner方法并返回父控件给IDE,以便TCarriageCollection属性能出现在Object Inspector中了。

  总结

  本章中我介绍了几乎所有VCL中重要的容器类,其中TList及其子类相当于通用的容器类,虽然不如C++和Java功能那么强大,但是用好了已经足以满足我们90%的开发需要,而TStrings及其子类,还有TCollection则是实现所见即所得设计的关键类,对于开发灵活强大的自定义组件来说是必不可少的。

上一篇:delphi容器类3
下一篇:Delphi RTTI 解析

图片内容