DOC

IMPLEMENTING TCOLLECTION

By Leon Spencer,2014-02-23 08:46
6 views 0
IMPLEMENTING TCOLLECTION

Implementing TCollection

    发信人: strayli (stray), 信区: Delphi

     : Implementing TCollection

    发信站: BBS 水木清华站 (Tue Sep 22 18:22:02 1998)

     This document is intended for those needing to descend from a class that manages an array of lightweight persistent objects of the same type. The class that best accomplishes this is TCollection and TCollectionItem. For example, TCollection is used to manage Panels in a TStatusBar, Columns in a TDBGrid, or Constraints in a TTable.

     This document begins with a discussion of the expected behavior of

    followed by a listing of the minimal steps TCollection descendants,

    necessary to implement a TCollection descendant, a listing of the component source, and finally some notes on design decisions and ideas for expansion of your TCollection descendant component. General Discussion

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

     To become familiar with the default behavior of TCollection, try adding a TStatusBar component to a form, click the ellipses of the Panels property, press the Add button of the "Editing Panels".

    This last step adds a TStatusPanel to the editor. Click on on the TStatusPanel item in the editor and notice the change in the object inspector. Instead of seeing TStatusBar now you will see StatusBar1.Panels[0] reflected in the Object Inspector.

     There are three major players involved with collections. A collection item (TCollectionItem) descendant, a TCollection that manages the list of TCollectionItems, and a component that contains the TCollection as one of it's properties. In our above example of TStatusBar, TStatusBar contains a descendant of TCollection called TPanels and TPanels manages a list of TCollectionItem descendants called TPanel. Notice that each TCollectionItem contains one or more properties; for instance, TPanels contains Alignment, Bevel, Style, Text, and Width properties. This list changes depending on the definition of your TCollectionItem descendant.

    Creating a Minimal TCollection Implementation

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

    In a new unit you must first define three new descendant classes from TCollectionItem, TCollection and a TComponent.

     TMyCollectionItem = class(TCollectionItem)

     TMyCollection = class(TCollection)

     TMyComponent = class(TComponent)

     To make TMyCollectionItem functional, you need to define one or more properties to contain information to be tracked by the collection mechanism. The example defines a Text and

    a MoreStuff integer property. You will also need to override the GetDisplayName method to supply the string shown for each item in the collection property editor:

     TMyCollectionItem = class(TCollectionItem)

     private

     FText: string;

     FMoreStuff: LongInt;

     function GetDisplayName: string; override;

     procedure SetText(const Value: string);

     procedure SetMoreStuff(const Value: LongInt);

     published

     property Text: string read FText write SetText;

     property MoreStuff: LongInt

     read FMoreStuff write SetMoreStuff;

     end;

     Next, define the TCollection descendant. This class will keep track of the component the collection belongs to, override the GetOwner method to accomodate streaming, and manage an array of the previously defined TCollectionItem descendants.

     You will need to define a new static constructor. The parameter passed in this constructor is the reference to the component that contains the collection. Also in the constructor you need to populate the ItemClass property with the class of your TCollection item descendant. Note: ItemClass returns the class (descended from TCollectionItem) to which the items in the collection belong.

     TMyCollection = class(TCollection)

     private

     FMyComponent: TMyComponent;

     function GetItem(Index: Integer): TMyCollectionItem;

     procedure SetItem(Index: Integer; Value: TMyCollectionItem);

     protected

     function GetOwner: TPersistent; override;

     public

     constructor Create(MyComponent: TMyComponent);

     function Add: TMyCollectionItem;

     property Items[Index: Integer]: TMyCollectionItem

     read GetItem write SetItem; default;

     end;

     Finally, define the component that will contain the collection. The component will contain a property descended from the TCollection type defined previously. The TCollection property will need a private field, an access method to the private field,

    and storage allocated in the constructor and freed in the destructor.

    Note: See The Developers Guide for more information on creating

    custom components.

     TMyComponent = class(TComponent)

     private

     FItems: TMyCollection;

     procedure SetItems(Value: TMyCollection);

     public

     constructor Create(AOwner: TComponent); override;

    destructor Destroy; override;

     published

     property Items: TMyCollection

     read FItems write SetItems;

     end;

    Complete Unit Listing

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

    unit Collec1;

    interface

    // Note: TCollection and TCollectionItem are defined in Classes.Pas.

    uses Classes;

    type

     TMyComponent = class;

     TMyCollectionItem = class(TCollectionItem)

     private

     FText: string;

     FMoreStuff: LongInt;

     function GetDisplayName: string; override;

     procedure SetText(const Value: string);

     procedure SetMoreStuff(const Value: LongInt);

     public

     published

     property Text: string read FText write SetText;

     property MoreStuff: LongInt read FMoreStuff write SetMoreStuff;

     end;

     TMyCollection = class(TCollection)

     private

     FMyComponent: TMyComponent;

     function GetItem(Index: Integer): TMyCollectionItem;

     procedure SetItem(Index: Integer; Value: TMyCollectionItem);

     protected

     function GetOwner: TPersistent; override;

     public

     constructor Create(MyComponent: TMyComponent);

     function Add: TMyCollectionItem;

     property Items[Index: Integer]: TMyCollectionItem

     read GetItem write SetItem; default;

     end;

     TMyComponent = class(TComponent)

     private

     FItems: TMyCollection;

     procedure SetItems(Value: TMyCollection);

     public

     constructor Create(AOwner: TComponent); override;

    destructor Destroy; override;

     published

     property Items: TMyCollection read FItems write SetItems;

     end;

     Register; procedure

    implementation

    procedure Register;

    begin

     RegisterComponents('Sample', [TMyComponent]); end;

    { TMyCollectionItem }

    // Note: Inherited default behavior of GetDisplayName is to // return the classname.

    function TMyCollectionItem.GetDisplayName: string; begin

     Result := Text;

     if Result = '' then Result := inherited GetDisplayName; end;

    procedure TMyCollectionItem.SetText(const Value: string); begin

     if FText <> Value then

     FText := Value;

    end;

    procedure TMyCollectionItem.SetMoreStuff(const Value: LongInt); begin

     if FMoreStuff <> Value then

     FMoreStuff:= Value;

    end;

    { TMyCollection }

    constructor TMyCollection.Create(MyComponent: TMyComponent); begin

     inherited Create(TMyCollectionItem);

     FMyComponent := MyComponent;

    end;

    function TMyCollection.Add: TMyCollectionItem; begin

     Result := TMyCollectionItem(inherited Add); end;

    function TMyCollection.GetItem(Index: Integer): TMyCollectionItem; begin

     Result := TMyCollectionItem(inherited GetItem(Index)); end;

    procedure TMyCollection.SetItem(Index: Integer;

     Value: TMyCollectionItem);

    begin

     inherited SetItem(Index, Value);

     end;

    // Note: You must override GetOwner in Delphi 3.x to get // correct streaming behavior.

    function TMyCollection.GetOwner: TPersistent; begin

     Result := FMyComponent;

    end;

    { TMyComponent }

    constructor TMyComponent.Create(AOwner: TComponent); begin

     inherited Create(AOwner);

     FItems := TMyCollection.Create(Self);

    end;

    destructor TMyComponent.Destroy;

    begin

     FItems.Free;

     inherited Destroy;

    end;

    procedure TMyComponent.SetItems(Value: TMyCollection); begin

     FItems.Assign(Value);

    end;

    end.

    {--------------------------------------------------------------------}

    Notes

    -----

     In this minimal example we didn't override the Assign method for the TCollectionItem, but this method should have further support. Here's an example of how you might implement Assign in the above project:

    procedure TMyCollectionItem.Assign(Source: TPersistent); begin

     if Source is TMyCollectionItem then

     begin

     Text := TMyCollectionItem(Source).Text;

     MoreStuff := TMyCollectionItem(Source).MoreStuff;

     Exit;

     end;

     inherited Assign(Source);

    end;

     Also not included in the above project is the logic needed to notify the TCollection class when one of it's contained items has

    This could be particularly important in a visual control changed.

    such as TStatusBar. TCollection supplies a virtual Update method for handling this behavior. See TStatusBar or THeaderControl in \source\vcl\commctrls.pas for further examples.

    --

    ※来源:?BBS 水木清华站 bbs.net.tsinghua.edu.cn?[FROM: 210.45.208.4]

Report this document

For any questions or suggestions please email
cust-service@docsford.com