如何从继承自另一个自定义控件的自定义控件触发方法?

时间:2014-11-12 19:43:03

标签: delphi

概述

为了更简单地将问题放入文本中,我的控件的继承如下所示:

TCustomListBox> TMyCustomListBox> TMyListBox

TMyCustomListBox的原因是通过添加一些我自己的新属性和方法来扩展TCustomListBox,然后我会得到其他TMyListBox组件,这些组件将派生自{{1} },但也可能有自己的属性和方法。

问题

我遇到的问题是无法从我在TMyCustomListBox中介绍的TMyListBox中触发该方法。

考虑到这一点,这里是TCustomListBox的细分摘要,您可以在其中看到我添加的新方法类型( OnAddition ):

TMyCustomListBox

我像这样分配事件:

type
  TOnAdditionEvent = procedure(Sender: TObject; Index: Integer; Value: string) of object;

  TMyCustomListBox = class(TCustomListBox)
  private
    FOnAddition: TOnAdditionEvent;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnAddition: TOnAdditionEvent read FOnAddition write FOnAddition;
    property OnClick;
    property OnDblClick;
    // ...
  end;

上述内容来自:

if Assigned(FOnAddition) then
begin
  FOnAddition(Self, SomeIndex, SomeValue);
end;

现在我们有procedure WndProc(var Message: TMessage); override;

TMyListBox

如果我在设计时使用type TMyListBox = class(TMyCustomListBox) public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; 的实例并使用新事件,那么在运行时测试时它会正常工作:

TMyListBox

如何在procedure Form1.MyListBox1Addition(Sender: TObject; Index: Integer; Value: string); begin ShowMessage('Added Item: [' + Value + '] whose index is: ' + IntToStr(Index)); end; 组件源代码中执行相同操作,我尝试了一些不同的操作,并且没有任何事情触发事件或我收到错误。


我尝试了什么

1

TMyListBox

2

与上述相同,仅添加type TMyListBox = class(TMyCustomListBox) protected procedure Addition(Sender: TObject; Index: Integer; Value: string); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; constructor TMyListBox.Create(AOwner: TComponent); begin inherited Create(AOwner); OnAddition := Addition; // shouldn't this call Addition procedure below? end; procedure TMyListBox.Addition(Sender: TObject; Index: Integer; Value: string); begin ShowMessage('test'); // doesnt fire end;

inherited

3

我尝试覆盖procedure TMyListBox.Addition(Sender: TObject; Index: Integer; Value: string); begin inherited; // no difference ShowMessage('test'); // doesnt fire end; 方法声明:

Addition

在基类中找不到procedure Addition(Sender: TObject; Index: Integer; Value: string); override; 的错误。

4

我甚至尝试将声明更改为:

Addition

并从构造函数中删除事件处理程序,仍然不会触发。

我也尝试了其他一些东西但是在这一点上我遇到了一个死胡同,所以会欣赏正确方向的推动。我真的应该能够解决这个问题,但我认为我已经花了太长时间坚持这个问题并且我的大脑正在融化,所以我等待最有可能变成一个简单明显的答案:)

感谢。

2 个答案:

答案 0 :(得分:6)

constructor TMyListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  OnAddition := Addition; // shouldn't this call Addition procedure below?
end;

这项任务应该可以正常工作。不,它不会调用 Addition()Addition()的地址分配给OnAddition事件。触发事件后,它将调用 Addition()

然而,话虽如此,这是错误的设计。组件应从不为其自己的事件(尤其是published事件)分配处理程序。正确的解决方案是让TMyCustomListBox声明一个触发virtual的{​​{1}}方法,然后在需要时调用该方法。 OnAddition(或任何其他后代)可以TMyListBox该方法,如果/想要触发用户的override事件处理程序,则调用inherited。额外的好处是,即使用户没有分配任何事件处理程序,这也允许后代对事件作出反应。

请改为尝试:

OnAddition

type
  TOnAdditionEvent = procedure(Sender: TObject; Index: Integer; Value: string) of object;

  TMyCustomListBox = class(TCustomListBox)
  private
    FOnAddition: TOnAdditionEvent;
  protected
    procedure DoAddition(Index: Integer; Value: string); virtual;
    property OnAddition: TOnAdditionEvent read FOnAddition write FOnAddition;
  // ...
  end;

procedure TMyCustomListBox.DoAddition(Index: Integer; Value: string);
begin
  if Assigned(OnAddition) then
   OnAddition(Self, Index, Value);
end;

答案 1 :(得分:1)

您的主要问题是,在TMyCustomListbox中,您将OnAdition声明为TOnAdditionEvent的属性,但在TMyListBox中,您尝试将此声明为过程。

所以正确的方法是声明你的TMyListBox如下:

type
  TMyListBox = class(TMyCustomListBox)
  protected
    procedure Addition(Sender: TObject; Index: Integer; Value: string);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnAddition; //This forwards the parent property definition to the child
  end;

constructor TMyListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  OnAddition := Addition; // shouldn't this call Addition procedure below?
end;

procedure TMyListBox.Addition(Sender: TObject; Index: Integer;
  Value: string);
begin
  ShowMessage('test'); // doesnt fire
end;

并在TMyListBox类调用之外触发事件:

MyListBox.OnAddition(Self, SimeIndex, SomeValue);

如果你是在课堂上这样做,你可以打电话:

Self.OnAddition(Self, SimeIndex, SomeValue);

注意:如果您想在子类中重用parent属性而不进行任何更改,请使用:

property MyParentProperyName;

您不需要声明属性类型,也不需要声明getter或setter方法,以便对属性的处理方式进行一些更改(例如,将完整的access属性从paret clas转换为仅在子类中读取) )。