delphi RTTI 读取属性 运行期
通过RTTI给属性赋值
http://docwiki.embarcadero.com/CodeExamples/Berlin/en/Event_RTTI_Invocation_(Delphi)
http://www.cnblogs.com/del/archive/2009/10/15/1583969.html
var context: TRttiContext; method: TValue; // System.TMethod methodType: TRttiInvokableType; begin { Get the value of the OnChange property, which is a method pointer } method := context.GetType(mapModel.ClassType).GetProperty('OnChange') .GetValue(mapModel); { Display the method code and data pair } Writeln(method.ToString); { Get event RTTI } methodType := context.GetType(method.TypeInfo) as TRttiInvokableType; Writeln(methodType.Name); { Invoke event } { The first parameter must be the procedure/method pointer in a TValue variable } methodType.Invoke(method, [mapModel { Sender } , nil { Area } ]);
读取简单属性
procedure TForm2.Button6Click(Sender: TObject); var rc: TRttiContext; v: TValue; rm: TRttiMethod; rt: TRttiType; rp: TRttiProperty; begin //取Btn2的属性Name 和Caption //分步 rt := TRttiContext.Create.GetType(self.Button2.ClassType); rp := rt.GetProperty('Name'); v := rp.GetValue(self.btn2); ShowMessage(v.AsString); //合并一步 ShowMessage( rt.GetProperty('Caption').GetValue(self.btn2).AsString); end;
修改属性
rt.GetProperty('Caption').SetValue(Button1,'New');
p.SetValue(Button1, TValue.FromOrdinal(TypeInfo(TAlign), Ord(alLeft)));
rc.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, TValue.From(Status));
const
eval = 'alLeft';
p.SetValue(Panel1, TValue.FromOrdinal( p.PropertyType.Handle , Ord(alLeft)));
两种方法都可以
// tv := TValue.FromOrdinal(p.PropertyType.Handle, GetEnumValue(p.PropertyType.Handle, eval));
// p.SetValue(Panel1, tv);
//调用btn2单击方法 procedure TForm2.Button7Click(Sender: TObject); var tt: TRttiType; rm: TRttiMethod; begin tt := TRttiContext.Create.GetType(self.btn2.ClassType); rm := tt.GetMethod('Click'); rm.Invoke(self.btn2, []);//空参 end;
TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray, tkUString,
tkClassRef, tkPointer, tkProcedure {, tkMRecord});
PropInfo.PropType^.Kind = tkClass
aRPt: TRttiProperty;
aRPt.PropertyType.Handle就是PTypeInfo
aRPt.PropertyType.Handle.Kind
设置复杂的属性字体颜色 字体 Font.Size/Font.Color
procedure TForm13.Button7Click(Sender: TObject); var p : TRttiProperty; p2: TRttiProperty; c : TRttiContext; begin c := TRttiContext.Create; try p := c.GetType(Panel1.ClassInfo).GetProperty('Font'); p2 := c.GetType(p.PropertyType.Handle).GetProperty('Color'); p2.SetValue(p.GetValue(Panel1).AsObject,clred); finally c.Free; end; end; procedure TForm13.Button8Click(Sender: TObject); var p : TRttiProperty; p2: TRttiProperty; c : TRttiContext; begin c := TRttiContext.Create; try // self.Panel1.Font.Style: p := c.GetType(Panel1.ClassInfo).GetProperty('Font'); p2 := c.GetType(p.PropertyType.Handle).GetProperty('Size'); p2.SetValue(p.GetValue(Panel1).AsObject,20); //this line now works. finally c.Free; end; end;
http://stackoverflow.com/questions/6006326/how-i-can-set-the-value-of-a-nested-property-using-the-rtti?answertab=votes#tab-top
复杂类型(集合类型)tkSet
与控件实例无关,只是计算集合类型的字符串。获得某个控件当前某个集合属性的字符串参考System.TypInfo.GetSetProp
procedure GetOrdTypeInfo(ATypeInfo: PTypeInfo; AStrings: TStrings); var OrdTypeData: PTypeData; I: Integer; begin OrdTypeData := GetTypeData(ATypeInfo); AStrings.Add('------------------------------------'); AStrings.Add('Type Name: ' + ATypeInfo^.Name); AStrings.Add('Type Kind: ' + GetEnumName(TypeInfo(TTypeKind), Integer(ATypeInfo^.Kind))); AStrings.Add('Data Type: ' + GetEnumName(TypeInfo(TOrdType), Integer(OrdTypeData^.OrdType))); if ATypeInfo^.Kind <> tkSet then begin AStrings.Add('Min Value: ' + IntToStr(OrdTypeData^.MinValue)); AStrings.Add('Max Value: ' + IntToStr(OrdTypeData^.MaxValue)); end; if ATypeInfo^.Kind = tkSet then GetOrdTypeInfo(OrdTypeData^.CompType^, AStrings); if ATypeInfo^.Kind = tkEnumeration then for I := OrdTypeData^.MinValue to OrdTypeData^.MaxValue do AStrings.Add(Format(' Value %d: %s', [I, GetEnumName(ATypeInfo, I)])); end; procedure TForm2.Button3Click(Sender: TObject); begin GetOrdTypeInfo(TypeInfo(Char), Memo1.Lines); GetOrdTypeInfo(TypeInfo(Integer), Memo1.Lines); GetOrdTypeInfo(TypeInfo(TFormBorderStyle), Memo1.Lines); GetOrdTypeInfo(TypeInfo(TBorderIcons), Memo1.Lines); GetOrdTypeInfo(TypeInfo(TMyEnum), Memo1.Lines); GetOrdTypeInfo(TypeInfo(TDBGridOption), Memo1.Lines); end;
TypeInfo(TPicture);
TypeInfo(TBitmap)
DBGrid
PropertyName:Options
Type Name: TDBGridOptions
Type Kind: tkSet
Data Type: otUWord
------------------------------------
Type Name: TDBGridOption
Type Kind: tkEnumeration
Data Type: otUByte
Min Value: 0
Max Value: 14
Value 0: dgEditing
Value 1: dgAlwaysShowEditor
Value 2: dgTitles
Value 3: dgIndicator
Value 4: dgColumnResize
Value 5: dgColLines
Value 6: dgRowLines
Value 7: dgTabs
Value 8: dgRowSelect
Value 9: dgAlwaysShowSelection
Value 10: dgConfirmDelete
Value 11: dgCancelOnExit
Value 12: dgMultiSelect
Value 13: dgTitleClick
Value 14: dgTitleHotTrack
gridEh控件
PropertyName:OptionsEh
Type Name: TDBGridEhOption
Type Kind: tkEnumeration
Data Type: otUByte
Min Value: 0
Max Value: 23
Value 0: dghFixed3D
Value 1: dghFrozen3D
Value 2: dghFooter3D
Value 3: dghData3D
Value 4: dghResizeWholeRightPart
Value 5: dghHighlightFocus
Value 6: dghClearSelection
Value 7: dghFitRowHeightToText
Value 8: dghAutoSortMarking
Value 9: dghMultiSortMarking
Value 10: dghEnterAsTab
Value 11: dghTraceColSizing
Value 12: dghIncSearch
Value 13: dghPreferIncSearch
Value 14: dghRowHighlight
Value 15: dghDblClickOptimizeColWidth
Value 16: dghDialogFind
Value 17: dghRecordMoving
Value 18: dghShowRecNo
Value 19: dghColumnResize
Value 20: dghColumnMove
Value 21: dghAutoFitRowHeight
Value 22: dghHotTrack
Value 23: dghExtendVertLines
通过RTTI给StringGrid单元格赋值
参考
http://stackoverflow.com/questions/15702778/how-can-i-set-get-property-value-through-rtti-for-compex-things-like-tstringgrid
var ctx: TRttiContext; rttitype: TRttiType; rttiprop: TRttiIndexedProperty; value: TValue; begin rttitype := ctx.GetType(StringGrid1.ClassType); rttiprop := rttitype.GetIndexedProperty('Cells'); value := rttiprop.GetValue(StringGrid1, [1, 1]); rttiprop.SetValue(StringGrid1, [1, 1], value.ToString + ' hello'); end;
判断属性类型
procedure DeserializeProperty(P: TRttiProperty; s: string); var v: TValue; begin case p.PropertyType.TypeKind of tkInteger: v := StrToInt(s); tkFloat: v := StrToFloat(s); tkString: v := s; end; p.SetValue(self, v); end;