The Wiert Corner – irregular stream of stuff

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

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

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

    Join 4,262 other subscribers

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. [/sourcecode] 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

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

  1. […] Below is first the simplified code based on Enum.GetValues, which isn’t really nice because extension methods can only be run on instances (they can not be true static methods like class helpers in Delphi can): […]

  2. 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

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

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

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

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

  7. 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).

  8. 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 :-)

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.