Class Delphi 2009:组件对象属性默认值

Class Delphi 2009:组件对象属性默认值,class,delphi,properties,components,delphi-2009,Class,Delphi,Properties,Components,Delphi 2009,如何设置组件对象属性值的默认值 组件类别代码: unit CustomClass; interface uses Classes; type TCustomClass = class; TConfiguration = class; TCustomClass = class (TComponent) private FConfiguration: TConfiguration; procedure SetConfiguration(const V

如何设置组件对象属性值的默认值

组件类别代码:

unit CustomClass;

interface

uses
    Classes;

type
  TCustomClass = class;

  TConfiguration = class;

  TCustomClass = class (TComponent)
  private
    FConfiguration: TConfiguration;
    procedure SetConfiguration(const Value: TConfiguration);
  published
    property Configuration: TConfiguration read FConfiguration write SetConfiguration;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  TConfiguration = class (TPersistent)
  private
    FDelay: Integer;
    FSize: Integer;
    procedure SetDelay(const Value: Integer);
    procedure SetSize(const Value: Integer);
  published
    property Delay: Integer read FDelay write SetDelay;
    property Size: Integer read FSize write SetSize;
  public
    procedure Assign(Source: TPersistent); override;
  end;

implementation

{ TCustomClass }

constructor TCustomClass.Create(AOwner: TComponent);
begin
  inherited;
  Configuration.FileName:= 'FileName';
  Configuration.Size := 10;
end;

destructor TCustomClass.Destroy;
begin
  Configuration.Free;
  inherited;
end;

procedure TCustomClass.SetConfiguration(const Value: TConfiguration);
begin
  FConfiguration.Assign(Value);
end;

{ TConfiguration }

procedure TConfiguration.Assign(Source: TPersistent);
begin
  inherited;
  Delay := (Source as TConfiguration).Delay;
  Size := (Source as TConfiguration).Size;
end;

procedure TConfiguration.SetDelay(const Value: Integer);
begin
  FDelay := Value;
end;

procedure TConfiguration.SetSize(const Value: Integer);
begin
  FSize := Value;
end;

end.
在我的IDE中,它将显示为修改了对象属性(蓝色粗体)

我认为在TConfiguration类属性上设置默认函数和存储函数时,如下所示:

t配置

interface

private
  function FileNameStored: Boolean;
published
  property FileName: string read FFileName write SetFileName stored FileNameStored;
  property Size: Integer read FSize write SetSize default 10;

implementation

function TConfiguration.FileNameStored: Boolean;
begin
  Result := FileName <> 'FileName';
end;
接口
私有的
函数FileNameStored:Boolean;
出版
属性文件名:字符串读取FFileName写入SetFileName存储FileNameStored;
属性大小:整数读取FSize写入SetSize默认值10;
实施
函数TConfiguration.FileNameStored:Boolean;
开始
结果:=文件名'FileName';
结束;
它将TConfiguration的属性涂成普通蓝色,但不是TCustomClass的配置属性,我不想在TCustomClass上设置其默认值,因为TConfiguration可能会在其他组件中使用

然后我还想,

TCustomClass

interface

private
  function ConfigurationStored: Boolean;
published
  property Configuration: TConfiguration read FConfiguration write SetConfiguration stored ConfigurationStored;

implementation

function TCustomClass.ConfigurationStored: Boolean;
begin
  Result := Configuration.FileName <> 'FileName' and
    Configuration.Size <> 10;
end;
接口
私有的
函数配置存储:布尔;
出版
属性配置:TConfiguration read FConfiguration write SetConfiguration storaged Configuration;
实施
函数TCustomClass.ConfigurationStored:布尔值;
开始
结果:=Configuration.FileName“FileName”和
配置。尺寸10;
结束;
但是,这仅将TCustomClass配置属性颜色设置为普通蓝色,而不是其属性

回答

正如@RemyLebeau指出的(在第一个和最上面的答案中),代码中存在错误。
在这种情况下,我决定不为属性设置任何默认值。

代码中有几个错误

  • 您的
    TCustomClass
    构造函数没有创建
    TConfiguration
    对象。您需要添加以下内容:

    constructor TCustomClass.Create(AOwner: TComponent);
    begin
      inherited;
      FConfiguration := TConfiguration.Create; // <-- add this
      FConfiguration.FileName := 'FileName';
      FConfiguration.Size := 10;
    end;
    
  • 您的
    t配置.Assign()
    方法实现不正确。通过在复制值之前调用继承的
    Assign()
    方法,如果调用方将一个
    t配置
    对象分配给另一个,则代码在运行时将始终引发
    EConvertError
    异常。原因是基类
    TPersistent.Assign()
    实现只调用
    Source.AssignTo(Self)
    ,而
    TConfiguration
    没有覆盖
    AssignTo()
    方法,因此调用
    TPersistent.AssignTo()
    ,它只调用
    Dest.AssignError(Self)
    ,这引发了一个例外。因此,如果
    实际上是
    t配置
    对象,则不要调用继承的
    Assign()
    方法:

    procedure TConfiguration.Assign(Source: TPersistent);
    begin
      if Source is TConfiguration then
      begin
        FDelay := TConfiguration(Source).Delay;
        FSize := TConfiguration(Source).Size;
      end else
        inherited;
    end;
    
  • 但是,这仅将
    TCustomClass
    配置
    属性颜色设置为普通蓝色,而不是其属性

    这是故意的。A仅适用于为其指定的属性

    将类与窗体上的
    TFont
    属性进行比较。当
    ParentFont
    True
    时,将不会存储
    Font
    属性。但是它的成员
    Color
    Name
    仍然不是默认的,因此它们看起来好像将被存储。这是因为
    TFont
    对象不知道其所有者,它怎么可能知道?一次是画布的一部分,另一次是控件的一部分,或者根本没有所有者。在所有这些条件下,
    TFont
    对象应该是完全功能的,因此它不会询问其父对象应该如何操作。另一方面:父母也不应该询问孩子如何表现


    现在回到您的场景:是否需要存储
    FileName
    Size
    属性应该在
    TConfiguration
    中处理。是否应存储
    TCustomClass
    Configuration
    属性可能不取决于这些
    FileName
    Size
    属性。如果存储了
    配置
    属性(粗体),但未存储其所有成员(非粗体),则最后不会存储任何内容。如果您有一个
    ParentConfiguration
    属性,就像
    ParentFont
    一样,您可以决定不存储
    Configuration
    属性。否则,就别管它了,不要让粗体进一步分散您的注意力。

    为什么我要将TConfiguration赋值从TCustomClass构造函数移到TConfiguration构造函数?这是编写组件类的常规方法吗?因为如果将来我创建另一个组件并使用相同的TConfiguration类,该怎么办?类的属性是该类的一个特征。该属性的默认值也是。这理由已经足够了。但特别是当您需要在多个场景中使用该类时,您应该将其设计为能够自主运行。因此,您可以在需要的类中创建一个
    t配置
    ,并在其中分配自定义设置,但默认设置是在
    t配置
    本身中进行的。这完全取决于您。如果一个绿色的苹果在果篮里需要是红色的,那么在装满果篮的时候把它变成红色。但是如果一个绿色的苹果应该有红色的斑点,那么你应该在做篮子之前设计一个有斑点的苹果。或者:如果篮子里装的是哪种类型的香蕉无关紧要,那么在装满篮子后登记香蕉类型。但是,当篮子中可能只有Chiquita香蕉时,则通过从TBanana设计一个TChiquitaBanana专门用于此类型篮子的TChiquitaBanana来实施该限制。您是否打算将配置对象放到窗体上,并将自定义类放到窗体上,然后连接它们?或者您希望配置对象是属于自定义类的属性,而不必手动创建和分配?然后您确实忽略了一些显而易见的事情,正如Remy指出的那样。他表明你需要解释
    procedure TConfiguration.Assign(Source: TPersistent);
    begin
      if Source is TConfiguration then
      begin
        FDelay := TConfiguration(Source).Delay;
        FSize := TConfiguration(Source).Size;
      end else
        inherited;
    end;