1

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

 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;

该组件编译和构建就好了。具有此组件的应用程序也可以正常编译和运行。如果我分配一个 OnClick 事件,它会起作用。所有其他事件,如果我分配它们并尝试运行应用程序,我会收到一条错误消息,指出该事件不存在

有谁知道这是为什么?

4

2 回答 2

6

对于新组件创建者来说,您犯了一个相当常见的错误。你违反了这条规则:

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

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

将事件声明为 Published 和 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/

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

于 2013-03-12T01:12:32.090 回答
2

什么是事件

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

我假设你在期待什么

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

当你分配它时,你正在做指针分配。举个例子,你的线

img.OnDblClick:= fOnImageDblClick;

使用当时的值执行指针赋值fOnImageDblClick。如果是nilimg.OnDblClick将从nil现在开始。如果它当时指向,则从现在开始将指向同一对象上的相同方法,但是,如果您稍后更改 fOnImageDblClick 指向的位置,则 imgOnDblClick 将不会跟随...它将仍然指向相同的地址。如果你想改变它,你也必须通过代码进行改变。Form1.MyComponentImageClickimg.OnDblClick

如果您希望这种情况发生,您可以在外部类的事件设置器中执行此操作。

首先,像这样声明您的事件:

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;
于 2013-03-12T00:00:45.887 回答