delphi - 带有TRectangle的GetPropList返回StrokeThickness作为属性,应作为Stroke类的一部分

标签 delphi rtti delphi-10-seattle

我正在使用Delphi Seattle Update1 Win64,并尝试使用RTTI提取属性。我的目标是将组件属性序列化为JSON,因为我需要在非Delphi环境中使用此信息。

我的问题是关于GetPropListTRectangle(示例)以及为什么它返回无法传递给GetPropValue的属性,即:


StrokeThickness作为类型tkFloat
StrokeCap作为类型tkEnumeration
StrokeDash作为类型tkEnumeration
StrokeJoin作为类型tkEnumeration。


GetPropList确实以Stroke类型正确返回了tkClass,这正是我所期望的,并且在解析后,Stroke类返回了ThicknessCapDashJoin,我可以得到从这些正确的值。

问题是在GetPropValue上执行StrokeThickness会导致异常。因此,在特殊情况下,我想避免GetPropList返回的“损坏”属性。

最初,我认为这是GetPropList返回一个不存在的属性的问题,但是我可以在代码中执行以下操作,并且它们都可以工作:

   Rectangle1.StrokeThickness := 5;   //works

   Rectangle1.Stroke.Thickness := 10; //and also works


tkFloat或tkEnumeration类型的其他属性按预期工作,并返回正确的值。

我创建了一个小型测试应用程序以尝试对其进行调试。我发现的是,在StrokeThickness的情况下,函数System.TypeInfo.TPropSet.GetProp(第2397行)中的M.Code为零,我猜这解释了为什么会导致异常。

随附的是我创建的测试代码,用于确认在较大项目中看到的内容。我如何处理上面列出的四个属性而没有特殊情况。

表格:

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 - 带有TRectangle的GetPropList返回StrokeThickness作为属性,应作为Stroke类的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35527220/

相关文章:

forms - 如何恢复自动创建表单列表和 DPR 初始化代码之间的同步?

德尔福2010 RTTI : Explore Enumerations

delphi - 模态按钮在表单上不起作用

c++ - C++ 中基类指针引用的对象的打印类型?

delphi - TCheckBox.Data 用作 TValue 时类型转换无效

Delphi 10 Seattle update1 IDE 高 dpi 支持

delphi - 如何停止在 Delphi 10 Seattle IDE 中创建 .stat 文件

delphi - 如何管理delphi单元中的循环引用?

android - 防止 FireMonkey 缩小照片

sql - 使用 Delphi TChart 显示数据库中的信息