7

I have values stored in xml and lua code and accessing object's properties through RTTI.

var
  o, v: TValue; // o is current object
  a: TStringDynArray; // params as array
  ctx: TRttiContext;
  tt: TRttiType;
  p: TRttiProperty;
  pt: PTypeInfo;
begin
...
  ctx := TRttiContext.Create;
  try
    o := GetLastClassInParams(ctx, obj, a, param_idx);
    tt := ctx.GetType(o.TypeInfo);
    if high(a) < param_idx then
        raise Exception.Create(S_FN + S_NOP);
    p := tt.GetProperty(a[param_idx]);
    if p = nil then
        raise Exception.Create(S_FN + S_PNE + a[param_idx]);
    pt := p.PropertyType.Handle;
    case p.PropertyType.TypeKind of
      tkInteger: v := TValue.From<integer>(integer(Value));
      tkEnumeration: v := TValue.FromOrdinal(pt, GetEnumValue(pt, VarToStr(Value)));
      tkUString: v := TValue.From<string>(VarToStr(Value));
      tkFloat: v := TValue.From<double>(double(Value));
      tkSet: begin
          temp_int := StringToSet(pt, VarToStr(Value));
          TValue.Make(@temp_int, pt, v);
        end;
    else v := TValue.FromVariant(Value);
    end;
    p.SetValue(o.AsObject, v);

I can work with many properties like Width, Lines.Text of TMemo etc, even with Panels[0].Width of TStatusBar (where Panels is TCollection descendant), but thing like TStringGrid.Cells[x, y] is something I can't solve. There is help on Embarcadero and some functions like GetIndexedProperty (maybe that is what I need), but explanation there as good as "Gets Indexed Property".

How to set and get TStringGrid.Cells[x,y] through RTTI at runtime if I have values stored as strings like "Cells[1,1]"?

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
user2091150
  • 978
  • 12
  • 25

1 Answers1

6

Here's the simplest example I can think off to get and set the values from a string grid using RTTI:

var
  ctx: TRttiContext;
  rttitype: TRttiType;
  rttiprop: TRttiIndexedProperty;
  value: TValue;
....
rttitype := ctx.GetType(StringGrid1.ClassType);
rttiprop := rttitype.GetIndexedProperty('Cells');
value := rttiprop.GetValue(StringGrid1, [1, 1]);
rttiprop.SetValue(StringGrid1, [1, 1], value.ToString + ' hello');

I excised the error checking for the sake of simplicity. I'm going to assume that you already know how to check for errors.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks. Is there any way to find when I should use GetIndexedProperty and when GetProperty? – user2091150 Mar 29 '13 at 12:32
  • 1
    OK, I'm guessing that you are parsing text like this: `Cells[1,1] := ...`. In which case the presence of `[]` tells you that it is an indexed property. You can also use `TRttiType.GetIndexedProperties` and check if your property is in that list. – David Heffernan Mar 29 '13 at 12:40
  • Yes, but was curious is Delphi knows that property is indexed and maybe RTTI can return somehow IsIndexed. Thanks. – user2091150 Mar 29 '13 at 12:48
  • I looked but could not find such a property – David Heffernan Mar 29 '13 at 13:03
  • Because there is problem: `TStatusBar.Panels[x]` is property and nil on attempt to read as `GetIndexedProperty('Panels')` while `TStringGrid.Cells[x,y]` is indexed property and nil on `GetProperty('Cells')`. I can't just get indexed and not indexed properties into arrays to search because they have different types. And array values is exact types used by different functions. Or - I can, but it have no sense. Only option is to get them both and decide by nil or not. – user2091150 Mar 29 '13 at 16:16
  • That's a sensible approach. Try both and whichever is non-nil is your guy. – David Heffernan Mar 29 '13 at 16:21
  • So far it works by non-nil and `result := TCollection(myObjAsTValue.AsObject).Items[x]` for ordinal properties where `myObjAsTValue.AsObject is TCollection`. – user2091150 Mar 29 '13 at 17:44