Delphi 2009:组件对象 属性 默认值
Delphi 2009: Component Object property default value
如何设置组件对象的默认属性值?
组件Class代码:
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 class 属性上创建默认函数和存储函数,如下所示:
配置
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 的配置 属性 并且它不在那里,我想设置它的默认值,在 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 配置 属性 颜色设置为普通蓝色,而不是其属性。
回答
正如@RemyLebeau 所指出的(在第一个也是最重要的答案中),代码中存在错误。
在那个组件和那种情况下,我决定不为属性设置任何默认值。
您的代码中有几个错误。
您的 TCustomClass
构造函数未创建 TConfiguration
对象。您需要添加:
constructor TCustomClass.Create(AOwner: TComponent);
begin
inherited;
FConfiguration := TConfiguration.Create; // <-- add this
FConfiguration.FileName := 'FileName';
FConfiguration.Size := 10;
end;
也就是说,FileName
和 Size
属性的赋值可能应该移至 TConfiguration
构造函数而不是 TCustomClass
构造函数。
A String
属性 不能用用户定义的默认值来定义,默认总是空字符串。因此,当您的组件创建时,您的 FileName
属性 将始终显示为已修改,因为您的构造函数正在为其分配非默认值。您的 stored
方法是处理该问题的正确解决方案。或者,不分配默认值 FileName at all
,将其留空。如果用户未指定显式 FileName
,您的代码可以根据需要采用默认值。
另一方面,Integer
属性可以使用用户定义的默认值来定义。不过,您的 Size
属性 并没有这样做。它应该是(特别是如果你将默认值的赋值移动到 TConfiguration
构造函数中):
property Size: Integer read FSize write SetSize default 10;
您的 TConfiguration.Assign()
方法实施不正确。通过在复制值之前调用继承的 Assign()
方法,如果调用者将一个 TConfiguration
对象分配给另一个对象,您的代码将始终在运行时引发 EConvertError
异常。原因是因为基本 class TPersistent.Assign()
实现只是调用 Source.AssignTo(Self)
,而 TConfiguration
没有覆盖 AssignTo()
方法,所以 TPersistent.AssignTo()
被调用,它只是调用 Dest.AssignError(Self)
,这会引发异常。因此,如果 Source
实际上是一个 TConfiguration
对象,请不要调用继承的 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;
But, this only sets the TCustomClass
Configuration
property color to normal blue, not its properties.
这是设计使然。 storage specifier 仅适用于指定的 属性。
将你 class 与 TFont
属性 在表格上进行比较。当ParentFont
为True
时,Font
属性不会被存储。但是它的成员 Color
和 Name
仍然不是默认的,因此它们看起来好像将被存储。这是因为 TFont
object 不知道它的所有者,怎么可能呢?一次是 canvas 的一部分,另一次是控件的一部分,或者根本没有所有者。在所有这些条件下,TFont
object 应该是完全可用的,所以它不会询问它的 parent 它应该如何表现。另一方面:parent 不应该询问它的 child 如何表现。
现在回到你的场景:FileName
和Size
属性是否需要存储应该在TConfiguration
中处理。是否应存储 TCustomClass
的 Configuration
属性 可能 而不是 取决于这些 FileName
和 Size
属性。如果 Configuration
属性 被存储(粗体),但它的所有成员都没有存储(非粗体),那么最后什么也没有存储。如果你有一个 ParentConfiguration
属性,类似 ParentFont
,那么你可以不存储 Configuration
属性。否则,随它去吧,让大胆不再分散你的注意力。
如何设置组件对象的默认属性值?
组件Class代码:
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 class 属性上创建默认函数和存储函数,如下所示:
配置
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 的配置 属性 并且它不在那里,我想设置它的默认值,在 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 配置 属性 颜色设置为普通蓝色,而不是其属性。
回答
正如@RemyLebeau 所指出的(在第一个也是最重要的答案中),代码中存在错误。 在那个组件和那种情况下,我决定不为属性设置任何默认值。
您的代码中有几个错误。
您的
TCustomClass
构造函数未创建TConfiguration
对象。您需要添加:constructor TCustomClass.Create(AOwner: TComponent); begin inherited; FConfiguration := TConfiguration.Create; // <-- add this FConfiguration.FileName := 'FileName'; FConfiguration.Size := 10; end;
也就是说,
FileName
和Size
属性的赋值可能应该移至TConfiguration
构造函数而不是TCustomClass
构造函数。A
String
属性 不能用用户定义的默认值来定义,默认总是空字符串。因此,当您的组件创建时,您的FileName
属性 将始终显示为已修改,因为您的构造函数正在为其分配非默认值。您的stored
方法是处理该问题的正确解决方案。或者,不分配默认值FileName at all
,将其留空。如果用户未指定显式FileName
,您的代码可以根据需要采用默认值。另一方面,
Integer
属性可以使用用户定义的默认值来定义。不过,您的Size
属性 并没有这样做。它应该是(特别是如果你将默认值的赋值移动到TConfiguration
构造函数中):property Size: Integer read FSize write SetSize default 10;
您的
TConfiguration.Assign()
方法实施不正确。通过在复制值之前调用继承的Assign()
方法,如果调用者将一个TConfiguration
对象分配给另一个对象,您的代码将始终在运行时引发EConvertError
异常。原因是因为基本 classTPersistent.Assign()
实现只是调用Source.AssignTo(Self)
,而TConfiguration
没有覆盖AssignTo()
方法,所以TPersistent.AssignTo()
被调用,它只是调用Dest.AssignError(Self)
,这会引发异常。因此,如果Source
实际上是一个TConfiguration
对象,请不要调用继承的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;
But, this only sets the
TCustomClass
Configuration
property color to normal blue, not its properties.
这是设计使然。 storage specifier 仅适用于指定的 属性。
将你 class 与 TFont
属性 在表格上进行比较。当ParentFont
为True
时,Font
属性不会被存储。但是它的成员 Color
和 Name
仍然不是默认的,因此它们看起来好像将被存储。这是因为 TFont
object 不知道它的所有者,怎么可能呢?一次是 canvas 的一部分,另一次是控件的一部分,或者根本没有所有者。在所有这些条件下,TFont
object 应该是完全可用的,所以它不会询问它的 parent 它应该如何表现。另一方面:parent 不应该询问它的 child 如何表现。
现在回到你的场景:FileName
和Size
属性是否需要存储应该在TConfiguration
中处理。是否应存储 TCustomClass
的 Configuration
属性 可能 而不是 取决于这些 FileName
和 Size
属性。如果 Configuration
属性 被存储(粗体),但它的所有成员都没有存储(非粗体),那么最后什么也没有存储。如果你有一个 ParentConfiguration
属性,类似 ParentFont
,那么你可以不存储 Configuration
属性。否则,随它去吧,让大胆不再分散你的注意力。