Yesterday I had to write a mapping from a set of radio buttons to an integer (and back). I couldn’t use TRadioGroup and so I had to iterate over controls to find out which one is checked. To do that, I used an enumeration helper which I wrote long time ago.
function TfrmColorRemappingDlg.GetMapping: integer;
var
ctrl: TControl;
begin
Result := 0;
for ctrl in EnumControls(Self, TRadioButton) do
if TRadioButton(ctrl).Checked then
Exit(ctrl.Tag);
end;
At that point I decided that this old-way enumeration is not good enough for the modern times. What I particularly dislike about it is that I know the type of objects enumerator will return (TRadioButton in this example) but I still have to cast the enumeration variable to that type. The solution is simple – use generics!
function TfrmColorRemappingDlg.GetMapping: integer;
var
ctrl: TRadioButton;
begin
Result := 0;
for ctrl in EnumControls<TRadioButton> do
if ctrl.Checked then
Exit(ctrl.Tag);
end;
Much nicer.
I have implemented new enumerator factory as a class helper for TWinControl. This helper returns a record which is at the same time an enumerator factory (it implements a GetEnumerator function) and an enumerator (implementing [Get]Current and MoveNext).
type
TControlEnumeratorFactory<T:TControl> = record
strict private
FIndex : integer;
FParent: TWinControl;
public
constructor Create(parent: TWinControl);
function GetCurrent: T;
function GetEnumerator: TControlEnumeratorFactory<T>;
function MoveNext: boolean;
property Current: T read GetCurrent;
end;
TWinControlEnumerator = class helper for TWinControl
public
function EnumControls: TControlEnumeratorFactory<TControl>; overload;
function EnumControls<T:TControl>: TControlEnumeratorFactory<T>; overload;
end;The implementation is pretty simple.
constructor TControlEnumeratorFactory<T>.Create(parent: TWinControl);
begin
FParent := parent;
FIndex := -1;
end;
function TControlEnumeratorFactory<T>.GetCurrent: T;
begin
Result := T(FParent.Controls[FIndex]);
end;
function TControlEnumeratorFactory<T>.GetEnumerator: TControlEnumeratorFactory<T>;
begin
Result := Self;
end;
function TControlEnumeratorFactory<T>.MoveNext: boolean;
begin
Result := false;
while FIndex < (FParent.ControlCount - 1) do begin
Inc(FIndex);
if FParent.Controls[FIndex].InheritsFrom(T) then begin
Result := true;
break; //while
end;
end; //while
end;
All this (and more) is available in the open-sourced GpVCL unit.
No comments:
Post a Comment