Fredrik Loftheim made an interesting observation to my previous article on TWinControl.Controls enumerator - namely that the enumerator factory doesn't have to be interface based. It can be replaced by a record. Source is almost the same as before, but we can skip the interface declaration. Generated code is simpler as the enumerator factory is simply allocated from the stack and automatically destroyed when it goes out of scope. No interface support and no reference counting is required. Simpler and faster, that's the way to go. interface
type TControlEnumerator = record strict private ceClass : TClass; ceIndex : integer; ceParent: TWinControl; public constructor Create(parent: TWinControl; matchClass: TClass); function GetCurrent: TControl; function MoveNext: boolean; property Current: TControl read GetCurrent; end;
TControlEnumeratorFactory = record strict private cefClass : TClass; cefParent: TWinControl; public constructor Create(parent: TWinControl; matchClass: TClass); function GetEnumerator: TControlEnumerator; end;
function EnumControls(parent: TWinControl; matchClass: TClass = nil): TControlEnumeratorFactory;
implementation
function EnumControls(parent: TWinControl; matchClass: TClass = nil): TControlEnumeratorFactory; begin Result := TControlEnumeratorFactory.Create(parent, matchClass); end;
constructor TControlEnumerator.Create(parent: TWinControl; matchClass: TClass); begin ceParent := parent; ceClass := matchClass; ceIndex := -1; end;
function TControlEnumerator.GetCurrent: TControl; begin Result := ceParent.Controls[ceIndex]; end;
function TControlEnumerator.MoveNext: boolean; begin Result := false; while ceIndex < (ceParent.ControlCount - 1) do begin Inc(ceIndex); if (ceClass = nil) or (ceParent.Controls[ceIndex].InheritsFrom(ceClass)) then begin Result := true; break; end; end; end;
constructor TControlEnumeratorFactory.Create(parent: TWinControl; matchClass: TClass); begin cefParent := parent; cefClass := matchClass; end;
function TControlEnumeratorFactory.GetEnumerator: TControlEnumerator; begin Result := TControlEnumerator.Create(cefParent, cefClass); end;
The new version of the TWinControl.Controls enumerator plus some other stuff is available at http://gp.17slon.com/gp/files/gpvcl.zip. Labels: Delphi, enumerators, programming, source code, utilities |
4 Comments:
Also why not add the function to the TWinControl class using a class helper, would make the code using it look nicer.
I'm trying not to use class helpers too much, mainly because of the weird implementation which only allows one active helper per class.
And in this case, there's not much difference between typing EnumControls(control) and control.EnumControls.
You can use the syntax
TYPE
THelperClass2 = CLASS HELPER(THelperClass1) FOR TClassToBeHelped
to have more than one active CLASS HELPER for a given class...
I'm aware of that.
The problem occurs when you have two class helpers for TWinControl in two different units, written by different authors. Then you have to manually change one of them to descend from the other class helper - and you have to do it every time the unit changes.
In my opinion a simple function is better and more stable.
Post a Comment
Links to this post:
Create a Link
<< Home