自定义组件TImage事件导致错误“不存在”

时间:2013-03-11 23:41:35

标签: delphi delphi-2010 vcl

我有一个包含以下事件的自定义组件

 private
    { Private declarations }
    ...
    fOnImageClick: TNotifyEvent;
    fOnImageMouseUp: TMouseEvent;
    fOnImageMouseDown: TMouseEvent;
    fOnImageMouseMove:  TMouseMoveEvent;
    fOnImageMouseEnter: TNotifyEvent;
    fOnImageMouseLeave: TNotifyEvent;
    fOnImageSelect: TNotifyEvent;
    fOnImageDblClick: TNotifyEvent;
  protected
    ...
  public
    { Public declarations }
     ...
  published
     ...
     property OnImageClick: TNotifyEvent read  fOnImageClick write  fOnImageClick;
     property OnImageSelect: TNotifyEvent read  fOnImageSelect write  fOnImageSelect;
     property OnImageDblClick: TNotifyEvent read  fOnImageDblClick write  fOnImageDblClick;
     property OnImageMouseDown: TMouseEvent read  fOnImageMouseDown write  fOnImageMouseDown;
     property OnImageMouseUp: TMouseEvent read  fOnImageMouseUp write  fOnImageMouseUp;
     property OnImageMouseMove:  TMouseMoveEvent read  fOnImageMouseMove write  fOnImageMouseMove;
     property OnImageMouseLeave: TNotifyEvent read  fOnImageMouseLeave write  fOnImageMouseLeave;
     property OnImageMouseEnter: TNotifyEvent read  fOnImageMouseEnter write  fOnImageMouseEnter;
  end;

我将它们分配给一个TImage,其父级是TPanel,父级是TScrollBox

 img:= TImage.Create(ThumbPnl);
 img.Parent:= ThumbPnl;
 img.Tag:= I;
 img.Align:= alClient;
 img.Stretch:= true;
 img.OnClick:= fOnImageClick;
 img.OnDblClick:= fOnImageDblClick;
 img.OnMouseEnter:= fOnImageMouseEnter;
 img.OnMouseLeave:= fOnImageMouseLeave;
 img.OnMouseDown:= fOnImageMouseDown;
 img.OnMouseUp:= fOnImageMouseUp;
 img.OnMouseMove:= fOnImageMouseMove;

组件编译和压缩就好了。使用此组件的应用程序也可以编译并运行jus fine。如果我分配一个OnClick事件,它的工作原理。所有其他事件,如果我分配它们并尝试运行应用程序,我会收到错误消息,说明该事件不存在

任何人都知道为什么会这样?

2 个答案:

答案 0 :(得分:6)

您正在为新组件创建者犯一个相当常见的错误。你违反了这条规则:

  

组件用户编写事件处理程序,组件编写器“触发”事件

在您的情况下,您正在做的是在您作为组件开发人员不应该这样做时分配事件。组件用户可以在OnClickOnDblClick等事件中分配代码。

您可以将事件声明为已发布和TNotifyEvent类型。

property OnSomeEvent: TNotifyEvent read FOnSomeEvent write FOnSomeEvent;

这就是创建事件所需要做的一切。你的工作是“解雇”他们;也就是说,让它们成为现实。

这是在适当的时候在您的组件中完成的。通常,你要做的是创建一个方法DoXXXXX,其中XXXXX就是正在发生的事情。所以你要创建

procedure TMyImage.DoSomeEvent;
begin
  if Assigned(FOnSomeEvent) then FOnSomeEvent(Self);
end;  

然后,在您的代码中,当应该触发事件时,您只需调用DoSomeEvent

现在,如果您想增强默认事件的功能,那么您需要覆盖触发事件的方法。

我讨厌这样做,但我的经典组件TSmiley简单明了地说明了这一点:

http://tsmiley.svn.sourceforge.net/viewvc/tsmiley/

看看那个例子,你应该看看如何创建事件。

答案 1 :(得分:2)

什么是活动

Delphi中的事件是一个方法指针。方法指针基本上是两个指针,一个指向您分配给事件的方法,另一个指向您指定的实时实例(对象)。

我认为你期待

我认为您希望内部对象中的事件跟随分配给外部对象的事件,并且不会自动发生。

分配时,您正在进行指针分配。举个例子,你的行

img.OnDblClick:= fOnImageDblClick;

执行当前值为fOnImageDblClick的指针赋值。如果是nil,则img.OnDblClick从现在开始为nil。如果当时指向Form1.MyComponentImageClickimg.OnDblClick将从现在起指向同一对象上的相同方法,,如果您以后更改fOnImageDblClick指向的位置,imgOnDblClick将不会跟随...它将保持指向相同的地址。如果您想要更改,您还必须通过代码进行更改。

如果您希望这样做,您可以在外部类的事件设置器中执行此操作。

首先,声明你的事件:

published
  ...
  property OnImageDblClick: TNotifyEvent read  fOnImageDblClick write  SetOnImageDblClick; 

...
procedure TMyClass.SetOnImageDblClick(Value: TNotifyEvent);
begin
  FOnImageDblClick := Value;
  //pass the new value to the inner object.
  if Assigned(Img) then
    Img.OnDblClick := Value;
end;

如果你的Img内部对象一直存在,你不需要FOnImageDblClick变量,你也可以为属性写一个getter并直接从内部对象获取值,就像这样:

function TMyClass.GetOnImageDblClick: TNotifyEvent;
begin
  Result := Img.OnDblClick;
end;