Acceder a las propiedades de un componente vía RTTI
Éste truco aparece debido a la necesidad de obtener vía RTTI la siguiente información: Lista de todas las propiedades de un componente.
Valor de una propiedad de un componente sin utilizar el método siguiente (*).
Una primera aproximación para obtener la propiedad (Left, por ejemplo) de un componente del que a priori no conocemos el tipo, es utilizar una estructura IF o CASE (método 1) similar a la siguiente:
1 2 3 4 5 6 7 8 | // Metodo 1 (*) // Segun el tipo de componente... if (comp is TEdit) then Result := TEdit(comp).Left; else if (comp is TLabel) then Result := TLabel(comp).Left; else if (comp is TButton) then Result := TButton(comp).Left; |
Está claro que éste método es poco eficiente, poco flexible (siempre podemos dejarnos algún tipo de componente) y poco ortodoxo.
¿Cómo debe hacerlo Delphi para mostrar las propiedades de un componente en el inspector de objetos (por ejemplo)?
La respuesta es RTTI. Se puede acceder a las propiedades de un componente (a partir de la clase) y del nombre de la propiedad, utilizando la siguiente función (he añadido un parámetro nuevo para obtener en la misma llamada la lista de todas las propiedades -TStrings-).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | {:Obtener la información de una propiedad a partir de la clase y el nombre; Ademas devuelve la lista de todas las porpiedades de ese control.} function GetRTTIControlInfo(AControl: TPersistent; propList:TStrings; AProperty: string): PPropInfo; var i: integer; props: PPropList; tData: PTypeData; begin // Inicial Result := nil; // No asignado el control ==> Salimos if (AControl = nil) or (AControl.ClassInfo = nil) then begin Exit; end; // Obtener la información tData := GetTypeData(AControl.ClassInfo); // Tipo desconocido o sin propiedades ==> Salimos if (tData = nil) or (tData^.PropCount = 0) then Exit; GetMem(props, tData^.PropCount * SizeOf(Pointer)); try GetPropInfos(AControl.ClassInfo, props); for i := 0 to tData^.PropCount - 1 do begin propList.Add(Props^[i]^.Name); with Props^[i]^ do begin if (Name = AProperty) then begin result := Props^[i]; end; end; end; finally FreeMem(props); end; end; |
Un ejemplo de utilización podría ser el siguiente:
(basta con un formulario que tenga un TButton y un TMemo)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | procedure TForm1.Button1Click(Sender: TObject); var pInfo: PPropInfo; propList:TStrings; PStr:String; begin // Crear la lista propList := TStringList.Create(); // protección para liberar try // Acceder a la info de la propiedad pInfo := GetRTTIControlInfo(Button1, propList, 'Left'); // La prop. encontrada es de tipo integer (debería ser, ya que es la // prop. Left) if (pInfo.PropType^^.Kind in [tkInteger]) then begin // Obtener PStr:= 'Left' + ' = ' + Format('%d', [GetOrdProp(Button1, pInfo)]); // Mostrar MessageDlg(PStr, mtInformation, [mbOK], 0); end; // Rellenar la lista de propiedades Memo1.Lines.Assign(propList); finally FreeAndNil(propList); end; end; |
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…