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

时间:2015-12-11 18:26:50

标签: 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 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类属性上创建默认和存储函数,如下所示:

TConfiguration

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;

它以正常蓝色为TConfiguration的属性着色,而不是TCustomClass的Configuration属性,并且我不想设置其默认值,在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;

但是,这只将TCustomClass配置属性颜色设置为正常蓝色,而不是其属性。

ANSWER

正如@RemyLebeau指出的那样(在第一个和最顶层的答案中),代码中存在错误。 在那个组件和那个案例中,我决定不为属性设置任何默认值。

2 个答案:

答案 0 :(得分:5)

您的代码中存在多个错误。

  1. 您的TCustomClass构造函数未创建TConfiguration对象。您需要添加:

    constructor TCustomClass.Create(AOwner: TComponent);
    begin
      inherited;
      FConfiguration := TConfiguration.Create; // <-- add this
      FConfiguration.FileName := 'FileName';
      FConfiguration.Size := 10;
    end;
    

    话虽这么说,FileNameSize属性的分配可能应该移到TConfiguration构造函数而不是TCustomClass构造函数。

  2. 无法使用用户定义的默认值定义String属性,默认值始终为空字符串。因此,在创建组件时,FileName属性将始终显示为已修改,因为构造函数正在为其分配非默认值。您的stored方法是解决这个问题的正确方法。或者,只是不指定默认FileName at all,将其留空。如果用户未指定显式FileName,则代码可以根据需要采用默认值。

    另一方面,Integer属性可以使用用户定义的默认值定义。但是,您的Size财产并没有这样做。它应该是(特别是如果您将默认值的赋值移动到TConfiguration构造函数中):

    property Size: Integer read FSize write SetSize default 10;
    
  3. 您的TConfiguration.Assign()方法实施不正确。通过在复制值之前调用继承的Assign()方法,如果调用者将一个EConvertError对象分配给另一个,则代码将始终在运行时引发TConfiguration异常。原因是基类TPersistent.Assign()实现只调用Source.AssignTo(Self)TConfiguration不会覆盖AssignTo()方法,因此调用TPersistent.AssignTo(),只调用Dest.AssignError(Self),它引发了异常。因此,如果Assign()实际上是Source对象,请不要调用继承的TConfiguration方法:

    procedure TConfiguration.Assign(Source: TPersistent);
    begin
      if Source is TConfiguration then
      begin
        FDelay := TConfiguration(Source).Delay;
        FSize := TConfiguration(Source).Size;
      end else
        inherited;
    end;
    

答案 1 :(得分:0)

  

但是,这只会将TCustomClass Configuration属性颜色设置为普通蓝色,而不是其属性。

这是设计上的。 storage specifier仅适用于为其指定的属性。

将您的类与表单上的TFont属性进行比较。如果ParentFontTrue,则不会存储Font属性。但其成员ColorName仍然不是默认值,因此它们看起来好像会被存储。这是因为TFont对象不知道它的拥有者,它怎么可能?有一次它是画布的一部分,另一次它是控件的一部分,或根本没有所有者。在所有这些条件中,TFont对象应该是完全正常的,因此它不会询问它的父对象应该如何表现。另一方面:父母不应该询问孩子如何表现。

现在回到您的方案:是否需要存储FileNameSize属性应在TConfiguration中处理。是否应存储Configuration的{​​{1}}属性取决于这些TCustomClassFileName属性。如果存储Size属性(以粗体显示),但未存储其所有成员(不是粗体),则最后不会存储任何内容。如果您有Configuration属性,类似ParentConfiguration,那么您可以决定不存储ParentFont属性。否则,请保持原样,让勇气不再分散您的注意力。