You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi FMX中TAlphaColor数组序列化及嵌套属性问题

Delphi FMX中TAlphaColor数组属性的序列化问题

背景

我正在开发Delphi FMX应用,需要给组件添加一个TAlphaColor数组类型的属性,定义为Colors: TArray<TAlphaColor>;。我想了解该属性在配套.fm文件中的存储方式,是否可以直接存储类似Colors: [125487, 159875]这样的数组值,以及具体格式。

我知道TPropertyEditor主要用于IDE自定义编辑器,不确定它是否会影响.fm文件的序列化/反序列化。

问题

  1. 是否可以在.fm文件中直接序列化TAlphaColor数组?
  2. 如果可以,如何在.fm文件中格式化数组以确保正确加载与保存?

后续尝试

我采用了Remy Lebeau建议的方案(稍作修改,使用WriteListBegin/WriteListEnd和ReadListBegin/ReadListEnd),当属性直接位于组件根节点时可以正常工作:

TALRectangle = class(TPersistent)
private
  FColors: TArray<TAlphaColor>;
  procedure ReadColors(Reader: TReader);
  procedure WriteColors(Writer: TWriter);
protected
  procedure DefineProperties(Filer: TFiler); override;
published
  property Colors: TArray<TAlphaColor> read FColors write SetColors stored IsColorsStored;
end;

对应的.fm文件内容:

object ALRectangle1: TALRectangle
  Colors = (
    123456,
    123457
  )
end;

但当属性位于嵌套组件结构中时(如下代码所示),读取属性时完全失败:

TALGradient = class(TPersistent)
private
  FColors: TArray<TAlphaColor>;
  procedure ReadColors(Reader: TReader);
  procedure WriteColors(Writer: TWriter);
protected
  procedure DefineProperties(Filer: TFiler); override;
published
  property Colors: TArray<TAlphaColor> read FColors write SetColors stored IsColorsStored;
end;

TALBrush = class(TPersistent)
private
  FGradient: TALGradient;
published
  property Gradient: TALGradient read FGradient write SetGradient;
end;

TALRectangle = class(TALControl)
private
  FFill: TALBrush;
public
  property Fill: TALBrush read FFill write SetFill;
end;

对应的.fm文件内容:

object ALRectangle1: TALRectangle
  Fill.Gradient.Colors = (
    123456,
    123457
  )
end;

请问嵌套属性序列化失败的原因是什么?


解答

1. 是否可在.fm文件中直接序列化TAlphaColor数组?

可以,但不能使用[125487, 159875]这种方括号格式。Delphi FMX的序列化系统对数组的标准存储格式是用圆括号()包裹元素,就像你在根节点属性中成功实现的那样。

2. fm文件中数组的正确格式化方式

数组属性在.fm文件中需遵循以下格式:

属性名 = (
    元素1,
    元素2,
    ...
)

元素可单独分行或放在同一行,换行更易读,元素间用逗号分隔即可。

嵌套属性序列化失败的原因

问题核心在于嵌套持久化对象的初始化时机:

  • 当使用DefineProperties注册自定义序列化方法时,Delphi的归档系统(TFiler)需要确保嵌套的持久化对象(此处为TALGradient)已被完全创建并初始化,才能调用其ReadColors方法。
  • 你的代码中,TALBrush的Gradient属性、TALRectangle的Fill属性如果没有在构造阶段自动创建实例,那么当归档系统尝试读取Fill.Gradient.Colors时,Gradient对象可能还未被初始化,直接导致读取失败。
  • 此外,若父对象的属性加载逻辑存在问题,子对象的自定义序列化方法也无法被正确触发。

修复方案

  1. 自动创建嵌套持久化对象
    修改TALBrush和TALRectangle的构造函数,确保嵌套对象在构造时自动实例化:

    TALBrush = class(TPersistent)
    private
      FGradient: TALGradient;
    public
      constructor Create; override;
      destructor Destroy; override;
    published
      property Gradient: TALGradient read FGradient write SetGradient;
    end;
    
    constructor TALBrush.Create;
    begin
      inherited;
      FGradient := TALGradient.Create;
    end;
    
    destructor TALBrush.Destroy;
    begin
      FGradient.Free;
      inherited;
    end;
    
    // 同理处理TALRectangle的Fill属性
    TALRectangle = class(TALControl)
    private
      FFill: TALBrush;
    public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;
      property Fill: TALBrush read FFill write SetFill;
    end;
    
    constructor TALRectangle.Create(AOwner: TComponent);
    begin
      inherited;
      FFill := TALBrush.Create;
    end;
    
    destructor TALRectangle.Destroy;
    begin
      FFill.Free;
      inherited;
    end;
    
  2. 检查Setter方法逻辑
    确保SetGradient和SetFill方法正确处理对象所有权,避免空引用或重复创建问题。

  3. 验证自定义序列化方法
    确保TALGradient中的ReadColors和WriteColors方法正确处理列表读写:

    procedure TALGradient.ReadColors(Reader: TReader);
    var
      Count, I: Integer;
      Color: TAlphaColor;
    begin
      Reader.ReadListBegin;
      Count := Reader.ReadInteger;
      SetLength(FColors, Count);
      for I := 0 to Count - 1 do
      begin
        Color := TAlphaColor(Reader.ReadInteger);
        FColors[I] := Color;
      end;
      Reader.ReadListEnd;
    end;
    
    procedure TALGradient.WriteColors(Writer: TWriter);
    var
      I: Integer;
    begin
      Writer.WriteListBegin;
      Writer.WriteInteger(Length(FColors));
      for I := 0 to High(FColors) do
        Writer.WriteInteger(Integer(FColors[I]));
      Writer.WriteListEnd;
    end;
    

内容的提问来源于stack exchange,提问作者zeus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:47:06