Я использую Delphi Seattle Update1 Win64 и пытаюсь извлечь свойства с помощью RTTI. Моя цель — сериализовать свойства компонента в JSON, потому что мне нужно использовать эту информацию в среде, отличной от Delphi.
Мой вопрос касается GetPropList
для TRectangle
(пример) и почему он возвращает свойства, которые затем нельзя передать GetPropValue
, а именно:
StrokeThickness
как типtkFloat
StrokeCap
как типtkEnumeration
StrokeDash
как типtkEnumeration
StrokeJoin
как тип tkEnumeration.
GetPropList
действительно правильно возвращает Stroke
как тип tkClass
, чего я и ожидал, и при анализе класс Stroke возвращает Thickness
, Cap
, Dash
и Join
, и я могу получить из них правильные значения.
Проблема в том, что выполнение GetPropValue
на StrokeThickness
вызывает исключение. Поэтому у меня есть особый случай "сломанных" свойств, возвращаемых GetPropList
, которых я хотел бы избежать.
Сначала я подумал, что это проблема с GetPropList, возвращающим несуществующее свойство, но я могу выполнить следующее в коде, и они оба работают:
Rectangle1.StrokeThickness := 5; //works
Rectangle1.Stroke.Thickness := 10; //and also works
Другие свойства типа tkFloat или tkEnumeration работают должным образом и возвращают правильные значения.
Я создал небольшое тестовое приложение, чтобы попытаться отладить это. Я обнаружил, что в случае StrokeThickness M.Code равен нулю в функции System.TypeInfo.TPropSet.GetProp (строка 2397), что, я думаю, объясняет, почему это вызывает исключение.
Прилагается тестовый код, который я создал, чтобы подтвердить то, что я видел в своем более крупном проекте. Как бы я обработал четыре свойства, перечисленные выше, без особого случая.
Форма:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 202
ClientWidth = 542
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object Rectangle1: TRectangle
Position.X = 40.000000000000000000
Position.Y = 40.000000000000000000
Size.Width = 97.000000000000000000
Size.Height = 97.000000000000000000
Size.PlatformDefault = False
end
object StrokeThickness: TButton
Position.X = 40.000000000000000000
Position.Y = 144.000000000000000000
Size.Width = 97.000000000000000000
Size.Height = 22.000000000000000000
Size.PlatformDefault = False
TabOrder = 1
Text = 'RTTI'
OnClick = StrokeThicknessClick
end
object Memo1: TMemo
Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
DataDetectorTypes = []
Position.X = 152.000000000000000000
Position.Y = 40.000000000000000000
Size.Width = 353.000000000000000000
Size.Height = 129.000000000000000000
Size.PlatformDefault = False
TabOrder = 2
Viewport.Width = 349.000000000000000000
Viewport.Height = 125.000000000000000000
end
end
Код теста:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
FMX.Controls.Presentation, FMX.Edit, FMX.Objects, FMX.ScrollBox, FMX.Memo;
type
TForm1 = class(TForm)
Rectangle1: TRectangle;
StrokeThickness: TButton;
Memo1: TMemo;
procedure StrokeThicknessClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses System.TypInfo;
{$R *.fmx}
procedure TForm1.StrokeThicknessClick(Sender: TObject);
var
vValue : String;
PropList : PPropList;
PropInfo : PPropInfo;
PropType : PPTypeInfo;
PropListCount : Integer;
I: Integer;
begin
memo1.Lines.Clear;
PropListCount := GetPropList(Rectangle1, PropList);
for I := 0 to PropListCount-1 do
begin
PropInfo := PropList^[I];
PropType := PropInfo^.PropType;
Memo1.Lines.Add('Name: '+String(PropInfo^.Name) );
Memo1.Lines.Add('PropType: '+String(PropInfo^.PropType^.Name) );
Memo1.Lines.Add('PropKind: '+GetEnumName(TypeInfo(TTypeKind), Ord(PropType^.Kind)) );
Memo1.Lines.Add('');
end;
vValue := GetPropValue(Rectangle1, 'Name'); //test string
Memo1.Lines.Add('Proprty Name = '+VarToStr(vValue) );
vValue := GetPropValue(Rectangle1, 'Height'); //test float
Memo1.Lines.Add('Property Height = '+VarToStr(vValue) );
vValue := GetPropValue(Rectangle1, 'Sides'); //test enumeration
Memo1.Lines.Add('Property Sides = '+VarToStr(vValue) );
//The following would cause an exception
{
vValue := GetPropValue(Rectangle1, 'StrokeThickness');
Memo1.Lines.Add('Property StrokeThickness ='+VarToStr(vValue));
}
Rectangle1.StrokeThickness := 5; //works ??
//Still fails after it was explicitly set
{
vValue := GetPropValue(Rectangle1, 'StrokeThickness');
Memo1.Lines.Add('Property StrokeThickness ='+VarToStr(vValue));
}
Rectangle1.Stroke.Thickness := 10; //and also works... as expected
//The following with cause an exception
{
vValue := GetPropValue(Rectangle1, 'StrokeDash');
Memo1.Lines.Add('StrokeDash = '+VarToStr(vValue) );
}
end;
end.
System.Rtti
вместо использования старого -стиль RTTI из модуляSystem.TypInfo
, посмотрите, не произойдет ли сбой на том же свойстве. - person Remy Lebeau   schedule 21.02.2016System.Rtti
, но я читал, что это несколько увеличивает размер кода, поэтому вместо этого я выбралSystem.TypInfo
. Я сравню, чтобы увидеть, есть ли влияние. - person Alain Thiffault   schedule 21.02.2016