GetPropList with TRectangle returns StrokeThickness as 属性 这应该是 Stroke class 的一部分
GetPropList with TRectangle returns StrokeThickness as property which should be part of Stroke class
我正在使用 Delphi Seattle Update1 Win64 并尝试使用 RTTI 提取属性。我的objective是将组件属性序列化为JSON,因为我需要在非Delphi环境中使用这些信息。
我的问题是关于 TRectangle
(示例)的 GetPropList
以及为什么它 return 的属性无法传递给 GetPropValue
,即:
StrokeThickness
作为类型 tkFloat
StrokeCap
作为类型 tkEnumeration
StrokeDash
作为类型 tkEnumeration
StrokeJoin
作为 tkEnumeration 类型。
GetPropList
正确地 returns Stroke
作为类型 tkClass
,这是我所期望的,并且在解析时,Stroke class return Thickness
、Cap
、Dash
和 Join
我可以从中得到正确的值。
问题是在 StrokeThickness
上执行 GetPropValue
会导致异常。因此,我必须对由 GetPropList
编辑的 "broken" 属性 return 进行特殊处理,我想避免这种情况。
起初我认为这是 GetPropList returning 一个不存在的 属性 的问题,但我可以在代码中执行以下代码并且它们都有效:
Rectangle1.StrokeThickness := 5; //works
Rectangle1.Stroke.Thickness := 10; //and also works
tkFloat 或 tkEnumeration 类型的其他属性按预期工作并且 return 正确的值。
我创建了一个小型测试应用程序来尝试对此进行调试。我发现在 StrokeThickness 的情况下,M.Code 在函数 System.TypeInfo.TPropSet.GetProp(第 2397 行)中为 nil,我想这解释了为什么会导致异常。
附件是我创建的测试代码,用于确认我在更大的项目中看到的内容。如果没有特殊情况,我将如何处理上面列出的四个属性。
表格:
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.
使用类似
的代码
var
LProperty: TRttiProperty;
LType: TRttiType;
LContext: TRttiContext;
LArray: TArray<TRttiProperty>;
begin
LContext := TRTTIContext.Create;
LType := LContext.GetType(TRectangle);
LArray := LType.GetDeclaredProperties;
for LProperty in LArray do
begin
Memo1.Lines.Add('Name: ' + LProperty.Name);
Memo1.Lines.Add('PropType: ' + LProperty.PropertyType.Name);
Memo1.Lines.Add('PropKind: ' + GetEnumName(TypeInfo(TTypeKind), Ord(LProperty.PropertyType.TypeKind)));
if LProperty.IsReadable then
begin
Memo1.Lines.Add('Value: ' + LProperty.GetValue(Rectangle1).ToString);
end
else
begin
Memo1.Lines.Add('Value of the property cannot be read');
end;
Memo1.Lines.Add('');
end;
end;
我正在使用 Delphi Seattle Update1 Win64 并尝试使用 RTTI 提取属性。我的objective是将组件属性序列化为JSON,因为我需要在非Delphi环境中使用这些信息。
我的问题是关于 TRectangle
(示例)的 GetPropList
以及为什么它 return 的属性无法传递给 GetPropValue
,即:
StrokeThickness
作为类型tkFloat
StrokeCap
作为类型tkEnumeration
StrokeDash
作为类型tkEnumeration
StrokeJoin
作为 tkEnumeration 类型。
GetPropList
正确地 returns Stroke
作为类型 tkClass
,这是我所期望的,并且在解析时,Stroke class return Thickness
、Cap
、Dash
和 Join
我可以从中得到正确的值。
问题是在 StrokeThickness
上执行 GetPropValue
会导致异常。因此,我必须对由 GetPropList
编辑的 "broken" 属性 return 进行特殊处理,我想避免这种情况。
起初我认为这是 GetPropList returning 一个不存在的 属性 的问题,但我可以在代码中执行以下代码并且它们都有效:
Rectangle1.StrokeThickness := 5; //works
Rectangle1.Stroke.Thickness := 10; //and also works
tkFloat 或 tkEnumeration 类型的其他属性按预期工作并且 return 正确的值。
我创建了一个小型测试应用程序来尝试对此进行调试。我发现在 StrokeThickness 的情况下,M.Code 在函数 System.TypeInfo.TPropSet.GetProp(第 2397 行)中为 nil,我想这解释了为什么会导致异常。
附件是我创建的测试代码,用于确认我在更大的项目中看到的内容。如果没有特殊情况,我将如何处理上面列出的四个属性。
表格:
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.
使用类似
的代码var
LProperty: TRttiProperty;
LType: TRttiType;
LContext: TRttiContext;
LArray: TArray<TRttiProperty>;
begin
LContext := TRTTIContext.Create;
LType := LContext.GetType(TRectangle);
LArray := LType.GetDeclaredProperties;
for LProperty in LArray do
begin
Memo1.Lines.Add('Name: ' + LProperty.Name);
Memo1.Lines.Add('PropType: ' + LProperty.PropertyType.Name);
Memo1.Lines.Add('PropKind: ' + GetEnumName(TypeInfo(TTypeKind), Ord(LProperty.PropertyType.TypeKind)));
if LProperty.IsReadable then
begin
Memo1.Lines.Add('Value: ' + LProperty.GetValue(Rectangle1).ToString);
end
else
begin
Memo1.Lines.Add('Value of the property cannot be read');
end;
Memo1.Lines.Add('');
end;
end;