The Wiert Corner – irregular stream of Wiert stuff

Jeroen Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My work

  • My badges

  • Twitter Updates

  • My Flickr Stream

    MPS_9791

    MPS_9795

    MPS_9793

    More Photos
  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 430 other followers

Delphi – class helper to add for … in support for TComponent.Components / ComponentCount

Posted by jpluimers on 2009/05/07

You might have discovered that I’m a fan of Delphi class helpers.

This is another case where I’d like to use the for … in statement: accessing the Components of a TComponent instance.

So I wanted to end up with this:

procedure MyForm.FormCreate(Sender: TObject);
var
  Component: TComponent;
begin
  for Component in Self do
  begin
  // business logic goes here
  end;
end;


in stead of this:

procedure MyForm.FormCreate(Sender: TObject);
var
  Component: TComponent;
  ComponentIndex: Integer;
begin
  for ComponentIndex := 0 to ComponentCount - 1 do
  begin
    Component := Components[ComponentIndex];
    // business logic goes here
    end;
  end;
end;

As the core explanation is in my post on Delphi – adding for … in support to TPageControl I’ll just explain the main difference compared to that post:

function TComponentEnumerator.MoveNext: Boolean;
begin
  Assert(FMaxValue = FComponent.ComponentCount - 1, 'ComponentCount changed during enumeration');
  // ...
end;

This extra assertion (which I forgot in the TPageControlEnumerator) is to protect against changes in the underlying components.

So this is the full code:

unit ComponentHelperUnit;

interface

uses
  Classes;

type
  TComponentEnumerator = class(TObject)
  strict private
    FMinValue: Integer;
    FMaxValue: Integer;
    FValue: Integer;
    FComponent: TComponent;
  public
    constructor Create(const Component: TComponent);
    function GetCurrent: TComponent;
    function MoveNext: Boolean;
    property Current: TComponent read GetCurrent;
  end;

  TComponentHelper = class helper for TComponent
  public
    function GetEnumerator: TComponentEnumerator;
  end;

implementation

{ TComponentHelper }

function TComponentHelper.GetEnumerator: TComponentEnumerator;
begin
  Result := TComponentEnumerator.Create(Self);
end;

{ TComponentEnumerator }

constructor TComponentEnumerator.Create(const Component: TComponent);
begin
  Assert(Assigned(Component), 'cannot enumerate nil FComponent');

  inherited Create();

  Self.FComponent := Component;
  FMinValue := 0;
  FMaxValue := Component.ComponentCount - 1;
  FValue := FMinValue - 1;
end;

function TComponentEnumerator.GetCurrent: TComponent;
begin
  Result := FComponent.Components[FValue];
end;

function TComponentEnumerator.MoveNext: Boolean;
begin
  Assert(FMaxValue = FComponent.ComponentCount - 1, 'ComponentCount changed during enumeration');
  Inc(FValue);
  Result := FValue <= FMaxValue;
end;

end.

What you probably have guessed from my posts so far, is that I usually have small units.
This is to keep myself focussed, and to make reuse easier.

–jeroen

11 Responses to “Delphi – class helper to add for … in support for TComponent.Components / ComponentCount”

  1. gabr said

    TComponent already contains component-enumerating enumerator, at least in Delphi 2007.

    There is no control-enumerating enumerator in TWinControl, though. Some time ago I used a similar technique to implement it: http://17slon.com/blogs/gabr/2008/02/twincontrolcontrols-enumerator.html

    • jpluimers said

      I know, and it is good you are the first one to notice.
      This blog was a first step to an enumerator that is a bit more complex.
      What I actually wanted todo (a blog is scheduled for next week) is this:

      for Component in Self.ComponentsOfType(TSQLQuery) do
      (Component as TSQLQuery).SQL[1] := FTableName;

      The solution is similar to what you did; so watch my blog next week :-)

  2. I hope to make my next video on for..in loops on TDataSets (using Class Helpers) based on a unit in Code Central (and one of the presentations in CodeRage III).

  3. [...] Comments Edelklaus on Delphi – class helper to…jpluimers on Delphi – class helper to…Alister Christie on Delphi – class helper [...]

  4. [...] far seems fairly straightforward, but partly because of that, I’m inclined to take issue with this sort of [...]

  5. [...] The Wiert Corner: adding for … in support for TComponent.Components [...]

  6. [...] always wondered why  - since the for … in statement was added to the structured statements part of the Delphi language – it is not [...]

  7. Basil said

    Hi,

    I know we can ovrride a method using Class Helper as below :

    TFormHelper = class helper for TCustomForm
    public
    end;

    TFooHelper = class helper (TFormHelper) for TCustomForm
    protected
    procedure DoCreate; overload;
    end;

    implementation

    procedure TFooHelper.DoCreate;
    begin
    inherited DoCreate;
    end;

    My doubt is : i have written above code to get fired for each form creation in my application. but it is not working correctly. can you please tell me what i miss here.. i wish the doCreate procedur of TCustom form get fired auto matically when a form creating in my application.

    many thanks

    • jpluimers said

      Since a class helper only works if it is visible, you have to make sure that for each form in your application, the TFormHelper is visible.
      You usually do that by including the unit of TFormHelper in the uses list for every form in your application.

      –jeroen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 430 other followers