在构造函数中获取组件名称?

时间:2013-01-28 17:34:58

标签: delphi custom-component

我正在创建一个从TCustomControl派生的自定义控件,例如:

type
  TMyCustomControl = class(TCustomControl)
private
  FText: string;
  procedure SetText(const Value: string);
protected
  procedure Paint; override;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property Text: string read FText write SetText;
end;

注意,上述内容对于示例来说是不完整的,以保持简短。

无论如何,在我的控制下,我有一个Paint事件,它使用Canvas.TextOut显示文本(来自FText字段)。

当我的组件被添加到Delphi表单设计器时(在任何用户可以对组件进行更改之前)我希望TextOut显示组件的名称--TButton,TCheckBox,TPanel等是这方面的例子及其标题属性。

如果我尝试在构造函数中将我的Component的名称分配给FText,则返回空,例如'';

constructor TMyCustomControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FText  := Name; //< empty string
  ShowMessage(Name); //< empty message box too
end;

如果我将FText := Name更改为FText := 'Name';,它会将文本输出到我的Component,所以我确实知道它在实际代码中不是问题,但显然这会输出'Name'而不是实际组件名称,如MyCustomControl1,MyCustomControl2等。

所以我的问题是,如何从构造函数事件中获取Component的名称?

4 个答案:

答案 0 :(得分:6)

构造函数运行时尚未分配Name属性。在设计时,在控件的构造函数退出后,在将组件放到Designer上之后,IDE会为Name属性赋值。在运行时,Name属性由DFM流系统设置,而后者也在构造函数退出后调用。

无论哪种方式,TControl.SetName()属性设置器验证新值,然后将新值设置为控件的Text属性,以匹配当前Text值与旧Name匹配的值1}}值和控件的ControlStyle属性包括csSetCaption标志(默认情况下它)。当Text属性因任何原因发生更改时,控件会自动向自身发送CM_TEXTCHANGED通知。您可以让控件捕获该消息并在其自身上调用Invalidate()以触发新的重绘。在Paint()处理程序内部,只需按原样绘制当前Name,无论它是什么值。如果它是空白的,那就这样吧。不要试图强迫Name,让VCL正常处理它。

答案 1 :(得分:5)

我认为处理此问题的正确方法是使用Text的继承CaptionTCustomControl属性,并确保csSetCaption {{1}已设置。

答案 2 :(得分:0)

要应用名称,您可以覆盖TComponent.Loaded方法。

但我不认为你应该将Name复制到Text。这些是语义上独立的属性,并且添加意外的绑定会对你有所影响。

而WMPaint方法应检查Text是否为空,然后再渲染Name,但不应更改Text的属性。

procedure TMyComponent.WMPaint; message WM_Paint; var InternalCaption: string;
begin
....
   InternalCaption := Self.Text;
   If InternalCaption = '' then InternalCaption := Self.Name;
   If InternalCaption = '' then InternalCaption := Self.ClassName;
....
   Self.Canvas.OutText(InternalCaption);

如果有的话 - 你应该保持属性分开只是因为Name := 'AAA'; Name := 'BBB';不应该使Text和name不同步。使用您的方法,第一个语句将解决文本,第二个语句将使实际名称更改后仍显示旧名称。

答案 3 :(得分:0)

非常简单的方法是覆盖方法SetName:

TMyCaptionString = type of WideString;

TMyLabel = class(TCustomControl)
private
  FCaption: TMyCaptionString;
  FCaptionAsName: Boolean;
  procedure SetCaption(Value: TMyCaptionString);
protected
  procedure SetName(const NewName: TComponentName); override;
public
  constructor Create(AOwner: TComponent); override;
  property Caption: TMyCaptionString read FCaption write SetCaption;
end;

implementation

constructor TMyLabel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csOpaque, csReplicatable,csSetCaption];
  FCaptionAsName := (csDesigning in ComponentState) and not (csReadingState in ControlState);
  ...
end;

procedure TMyLabel.SetName(const NewName: TComponentName);
begin
  if FCaptionAsName then
  begin
    FCaptionAsName := FCaption = Name;
    FCaption := NewName;
    invalidate;
  end;
  inherited SetName(NewName);
end;

procedure TMyLabel.SetCaption(Value: TMyCaptionString);
begin
  if FCaption <> Value then
  begin
    FCaption := Value;
    Invalidate;
    FCaptionAsName := False;
  end;
end;

我需要自己的Caption poreprty变量,因为我想使用宽字符串代替unicode并编写自定义属性编辑器。对不起,我正在撰写旧话题,但我希望这会有所帮助。