首页 > 解决方案 > 设置基类属性时调用子类方法

问题描述

我正在创建自定义组件。此自定义组件继承自具有 TAlign 属性的 TControl。每当设置 TAlign 值时,我想从我的降级类中执行一个方法

这是降级的草稿:

  TWidget = class(TControl)
  public
    procedure Resize;
  end;

当我将值写入 TAlign(来自 TControl 类)时,会调用来自 TWidget 的另一个方法。像这样:

var
   t: TWidget;
begin
   t := TWidget.Create(Self);
   t.Align := alRight; // When this is executed, "Resize" from TWidget should be called

标签: delphi

解决方案


当控件的Align属性发生变化时,它会调用控件的方法SetBounds()RequestAlign()方法。

SetBounds()virtual,所以后代可以override直接。这也是控件的LeftTopWidthHeight属性设置器调用的相同方法。应用新边界后,向控件SetBounds()发出WM_WINDOWPOSCHANGED消息(可以通过override控件的虚WndProc()方法,或通过子类化其WindowProc属性,或通过声明message处理程序来捕获),以及调用RequestAlign()Resize()方法。

RequestAlign()调用Parent.AlignControl(),它做了很多工作,但它基本上归结为简单地重新定位每个Parent可见的子控件,基于它们各自的值AlignAnchors值。这些重新定位是通过调用SetBounds()每个子控件来完成的。

Resize()仅触发控件的OnResize事件处理程序(如果已分配)。

因此,让您的自定义控件对其大小或位置的变化做出反应的最佳方式是简单地处理overrideSetBounds()方法或处理WM_WINDOWPOSCHANGED消息,例如:

type
  TWidget = class(TControl)
  public
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  end;

procedure TWidget.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  // use Left/Top/Width/Height properties as needed...
end;

或者:

type
  TWidget = class(TControl)
  protected
    procedure WndProc(var Message: TMessage); override;
  end;

procedure TWidget.WndProc(var Message: TMessage);
begin
  inherited WndProc(Message);
  if Message.Msg = WM_WINDOWPOSCHANGED then
  begin 
    // use Left/Top/Width/Height properties as needed...
  end;
end;

或者:

type
  TWidget = class(TControl)
  private
    procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
  end;

procedure TWidget.WMWindowPosChanged(var Message: TWMWindowPosChanged);
begin
  inherited;
  // use Left/Top/Width/Height properties as needed...
end;

推荐阅读