我有一个包含以下事件的自定义组件
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事件,它的工作原理。所有其他事件,如果我分配它们并尝试运行应用程序,我会收到错误消息,说明该事件不存在
任何人都知道为什么会这样?
答案 0 :(得分:6)
您正在为新组件创建者犯一个相当常见的错误。你违反了这条规则:
组件用户编写事件处理程序,组件编写器“触发”事件
在您的情况下,您正在做的是在您作为组件开发人员不应该这样做时分配事件。组件用户可以在OnClick
,OnDblClick
等事件中分配代码。
您可以将事件声明为已发布和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.MyComponentImageClick
,img.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;