Delphi 2009 - 在自定义 Delphi 组件中设置默认属性值

Posted

技术标签:

【中文标题】Delphi 2009 - 在自定义 Delphi 组件中设置默认属性值【英文标题】:Delphi 2009 - Set default property values in custom delphi components 【发布时间】:2010-11-23 12:36:34 【问题描述】:

这应该很简单,但我找不到我想要的确切答案。我有一个基于 TSpeedButton 的自定义 delphi 控件。我希望 SpeedButton 的 Caption 属性始终为“Comments”,但我不想在运行时设置它我想在组件本身中设置它,以便当我将它放在我的表单上时它已经填充了这个文本。我也想设置按钮的高度和宽度,但我想这样做的方法与设置标题的方法相同。

为了完整起见,这里是组件代码:

unit CustomSpeedButton;

interface

uses
  SysUtils, Classes, Controls, Buttons;

type
  TCustomSpeedButton = class(TSpeedButton)
  private
    FCommentText: string;
    FCommentTitle: string;

    procedure SetCommentText(const Value: string);
    procedure SetCommentTitle(const Value: string);

     Private declarations 
  protected
     Protected declarations 
  public
     Public declarations 

  published
     Published declarations 
    property CommentTitle: string read FCommentTitle write SetCommentTitle;
    property CommentText: string read FCommentText write SetCommentText;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TCustomSpeedButton]);
end;

 TCustomSpeedButton 

procedure TCustomSpeedButton.SetCommentText(const Value: string);
begin
  FCommentText := Value;
end;

procedure TCustomSpeedButton.SetCommentTitle(const Value: string);
begin
  FCommentTitle := Value;
end;

end.

【问题讨论】:

您的意思是您希望默认 标题为“评论”,还是您的意思是您希望标题始终 为“评论” , 不管开发者以后改成什么? 默认标题为“评论” 【参考方案1】:

您需要在组件的构造函数中设置原始值。

编辑:您还需要将 ControlStyle := ControlStyle - [csSetCaption]; 添加到构造函数中。

【讨论】:

@Mason:这并不总是有效的。调用构造函数,然后在流入 DFM 时设置属性。您在构造函数中执行的操作可以替换为 DFM 中的内容。 是的,这是预期和期望的行为。如果用户在属性中输入内容、保存、重新加载,并且他们保存的内容已更改,他们会很生气。 我以前读过它应该在构造函数中完成,我发誓我以前知道它在哪里,但现在我正在努力寻找它! 它不存在是因为您还没有编写它。在类上声明一个构造函数,如下所示:constructor Create(AOwner: TComponent); override; 让它调用继承的构造函数,然后设置默认值。 呵呵,显然我需要去找一个“Delphi for Dummies”或类似的参考资料!这就是我需要的信息,梅森。谢谢!【参考方案2】:

由于您希望正确完成 Caption 属性,因此 Mason 的答案不会起作用,因为他错过了“csSetCaption”的事情,而且他关于“默认”的建议也不起作用,因为 Caption 和您的属性都是字符串类型。

以下是您想要的单位。

行为如下:

    最初 Caption 属性的值为“Comments” 用户可以在设计时通过设置一个新值来覆盖它

(如果您不想要 2.,那么您需要像 Ken 提到的那样在覆盖的 Loaded 方法中分配 Caption 属性;但是,您的问题并不清楚您是否想要这样做。如果您这样做,请改写你的问题。)

这就是代码的工作方式。

对于字符串属性,您不能提示任何默认的流系统。 但是您可以在构造函数中设置设计时的初始值:Caption := DefaultCustomSpeedButtonCaption;

对于 Caption 属性,您还必须禁用 Caption 属性的默认分配(否则您的组件将自动获得类似“CustomSpeedButton1”的标题)。 这行代码会为您做到这一点:ControlStyle := ControlStyle - [csSetCaption];

最后,最好将您的组件注册拆分为一个单独的单元。 这允许您拥有一个在 IDE 中注册组件的设计时包和一个用于在应用程序中使用组件的运行时包(或根本没有包)。

如果你有一个组件图标,那么你也可以在注册单元中加载它(因为它只在设计时需要)。

Ray Konopka 写了一本关于组件编写的优秀书籍,它仍然非常有效:Developing Custom Delphi 3 Components 像许多优秀的 Delphi 书籍一样,它已绝版,但您可以order a PDF copy on his site。

我不确定您的 CommentTitle 和 CommentText 属性的用途,所以我将它们保存在下面的源代码中。

清单 1:实际组件

unit CustomSpeedButtonUnit;

interface

uses
  SysUtils, Classes, Controls, Buttons;

const
  DefaultCustomSpeedButtonCaption = 'Comments';

type
  TCustomCustomSpeedButton = class(TSpeedButton)
  strict private
    FCommentText: string;
    FCommentTitle: string;
  strict protected
    procedure SetCommentText(const Value: string); virtual;
    procedure SetCommentTitle(const Value: string); virtual;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property CommentTitle: string read FCommentTitle write SetCommentTitle;
    property CommentText: string read FCommentText write SetCommentText;
  end;

  TCustomSpeedButton = class(TCustomCustomSpeedButton)
  published
// note you cannot use 'default' for string types; 'default' is only valid for ordinal ordinal, pointer or small set type
// [DCC Error] CustomSpeedButtonUnit.pas(29): E2146 Default values must be of ordinal, pointer or small set type
//    property Caption default DefaultCustomSpeedButtonCaption;
    property CommentTitle;
    property CommentText;
  end;

implementation

constructor TCustomCustomSpeedButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Caption := DefaultCustomSpeedButtonCaption;
  ControlStyle := ControlStyle - [csSetCaption];
end;

destructor TCustomCustomSpeedButton.Destroy;
begin
  inherited Destroy;
end;

procedure TCustomCustomSpeedButton.SetCommentText(const Value: string);
begin
  FCommentText := Value;
end;

procedure TCustomCustomSpeedButton.SetCommentTitle(const Value: string);
begin
  FCommentTitle := Value;
end;

end.

清单 2:组件注册

unit CustomSpeedButtonRegistrationUnit;

interface

procedure Register;

implementation

uses
  CustomSpeedButtonUnit;

procedure Register;
begin
  RegisterComponents('Standard', [TCustomSpeedButton]);
end;

end.

【讨论】:

谢谢杰罗恩。在几次错误的开始之后,我得出的结论是我只是要求太多,最后只是在将所有按钮粘贴到页面并将它们的特征更改为“批次”后选择了所有按钮。不过,您在上面给出的完整清单表明一切都没有丢失,因此我感谢您的意见。此外,我实际上拥有一本关于 Delphi 3 组件的书(D3 是我在 98 年左右第一次接触 Delphi).. 我从来没有时间阅读它,但现在会这样做! 嗯,很有趣。我启动了一个新组件以按照您的方式进行尝试,在创建组件注册单元然后保存并尝试切换到另一个项目之后,IDE 将我踢了出去,现在不会重新启动.. 唯一不同的是我做的不同是将注册过程修改为说'开始注册;结尾;'因为 registercomponents 不断抛出关于它无法识别的错误。必须以某种方式清除 IDE 缓存.. 糟糕 - 如果您执行“程序注册;开始注册;结束;”然后你得到一个无限循环。当您将这样的循环放入 IDE 中加载的设计时包中时,IDE 将挂起。最好的解决方案是关闭 Delphi IDE,找到你进入无限循环的组件包 .bpl,然后删除该 .bpl 文件,然后启动 Delphi IDE。希望有帮助。如果没有,请给我发一封电子邮件(pluimers dot com 上的几乎所有内容都会联系到我,但最简单的方法是使用我的名字)。我可以与您进行 TeamViewer 会话来解决它。好运! --jeroen 三年后但仍然相关:在我们希望用户能够用空白字符串覆盖默认属性的情况下,上述内容不起作用。似乎没有办法在字符串属性上使用 stored/default/nodefault,因此无法告诉流系统字符串属性的默认值是非空白的。如果我们将字符串属性设置为空白,则它不会存储在流中,因此我们在构造函数中设置的任何内容都会再次返回。为了避免这种情况,我在删除控件后从设计器触发的事件中设置默认值。 对不起,我还没有标准 IDE 的解决方案。我的应用程序克隆了 Delphi 表单设计器,因此当我将新控件拖放到表单上时,我可以插入自己的事件代码。也许有一个类似的事件或接口可以与由Delphi IDE触发的TControl一起使用,如果我找到它,我会在这里给出答案。【参考方案3】:

@Etherman:如果您想要一个具有默认值的字符串属性并且您想要将其保存到 DFM - 即使它是空白的 - 您必须自己做。幸运的是,Delphi 为您提供了执行此操作的方法。看看这段代码:

type
  TMyComp = class(TControl)
  private
    FMyStringProperty: string;
    procedure WriteMyStringProperty(Writer: TWriter);
    procedure DefineProperties(Filer: TFiler);  override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property MyStringProperty: string read FMyStringProperty write FMyStringProperty stored False;
  end;


implementation


constructor TMyComp.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FMyStringProperty := 'my default value';
end;

procedure TMyComp.WriteMyStringProperty(Writer: TWriter);
begin
  Writer.WriteString(FMyStringProperty);
end;

procedure TMyComp.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);
  Filer.DefineProperty('MyStringProperty', nil, WriteMyStringProperty, True);
end;

【讨论】:

以上是关于Delphi 2009 - 在自定义 Delphi 组件中设置默认属性值的主要内容,如果未能解决你的问题,请参考以下文章

在自定义 Delphi 组件中实现 Columns.Columns 属性

Delphi DLL Project在自定义BPL中找不到单元,除非“Link with Runtime Packages”为True

如何在 Delphi 2009 中对自定义组件进行鼠标平移

Delphi 2009:传递组件名称 onclick 事件然后设置属性

Delphi 2009 RAD Studio - 桌面选择器不工作

如何在 Delphi 2010 ( UniSynEdit Package ) 中安装 Delphi 2009 组件包?