Modificar propiedades de controles en ejecución utilizando RTTI

A veces durante la ejecución de código necesitamos modificar una determinada propiedad de diferentes tipos de controles. Para la explicación podemos pensar por ejemplo en como desactivar (Enabled=False) todos los controles de un formulario; Una primera opción podría ser un código como éste:

 // recorrer los controles
for i := 0 to (Self.ComponentCount - 1) do begin

// Es un Edit
if (Components[i] is TEdit) then
TEdit(Components[i]).Enabled := False;
// Es un LAbel
if (Components[i] is TLabel) then
TLabel(Components[i]).Enabled := False;
// Es un ListBox
if (Components[i] is TListBox) then
TListBox(Components[i]).Enabled := False;

...
end;

    Una implementación como ésta tiene muchos problemas e inconvenientes; Los más claros podrían ser:
    Utilizando RTTI podemos de forma relativamente sencilla modificar todos los componentes utilizando una única instrucción.
    Podemos utilizar un procedimiento como éste:

// ================================================================
{:Asigna valor a una propiedad a través del Nombre (RTTI). }
function SetPropAsString(AObj: TObject; const PropName, Value: String):Boolean;
var
PInfo: PPropInfo;
begin
// Intentamos acceder (con un puntero) a la info. de la propiedad
PInfo := GetPropInfo(AObj.ClassInfo, PropName);
Result := PInfo <> nil;
// Se ha obtenido la información...
if (Result) then begin
// Se ha encontrado la propiedad con éste nombre; Chequear el tipo...
if (PInfo^.Proptype^.Kind = tkString) or
(PInfo^.Proptype^.Kind = tkLString) then begin
// Asignar el valor de tipo String
SetStrProp(AObj, PInfo, Value);
end
else if (PInfo^.Proptype^.Kind = tkInteger) then begin
// Asignar el valor...
if (PInfo^.PropType^.Name = 'TColor') then begin
SetOrdProp(AObj, PInfo, StringToColor(Value));
end
else if (PInfo^.PropType^.Name =
'TCursor') then begin
SetOrdProp(AObj, PInfo, StringToCursor(Value));
end
else begin
SetOrdProp(AObj, PInfo, StrToInt(Value));
end;
end
else if (PInfo^.Proptype^.Kind = tkEnumeration) then begin
// Bloque de proteccion
try
if (PInfo^.PropType^ = TypeInfo(System.Boolean)) then begin
SetOrdProp(AObj, PInfo, StrToInt(Value));
end
else begin
SetOrdProp(AObj, PInfo, StrToInt(Value));
end;
except
raise;
end;
end
else begin
Result := False;
end;
end
else begin
// No se ha encontrado la propiedad con ese nombre
Result := False;
end;
end;

// ================================================================

Su utilización es muy sencilla, y en el ejemplo anterior el código utilizado pasaría a ser similar a éste:

NOTA: Añadir la unit TypInfo al USES.

 // recorrer los controles
for i := 0 to (Self.ComponentCount - 1) do begin
SetPropAsString(Components[i],
'Enabled', '0'{Entero correspondiente a FALSE});
end;

// Otros ejemplos
SetPropAsString(Components[i], 'Left', '10');
SetPropAsString(Components[i],
'Color', 'clRed');
...


  Indice