【问题标题】:Custom Component TImage events causing error "Does not exist"自定义组件 TImage 事件导致错误“不存在”
【发布时间】:2013-03-11 23:41:35
【问题描述】:

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

 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 事件,它会起作用。所有其他事件,如果我分配它们并尝试运行应用程序,我会收到一条错误消息,指出该事件不存在

有人知道这是为什么吗?

【问题讨论】:

  • 请给出确切的错误信息。不要描述错误信息。引用它们。逐字逐句。

标签: delphi delphi-2010 vcl


【解决方案1】:

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

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

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

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

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

【讨论】:

  • +1 表示“我讨厌这样做”和经典的 Tsmiley 组件。 :p
  • 这个问题描述了一个不同的场景。 Q 中的代码希望用户事件在图像事件触发时触发。所以需要将图像事件设置为组件中定义的处理程序。他们反过来跳 if Assigned(FOnSomeEvent) then FOnSomeEvent(Sender); 舞蹈。
【解决方案2】:

什么是事件

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

我猜你期待什么

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

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

img.OnDblClick:= fOnImageDblClick;

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

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

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

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;

【讨论】:

  • 不幸的是,创建 img 并将所有事件分配给它的代码片段在组件的受保护方法 (UpdateViewer) 中循环。它们可以有 n 个。这是一个图像查看器组件。因此,我无法在 setter 方法中访问它 - 我会吗?还有其他方法吗?
  • 我将 img 变量从它在本地的位置移动到组件的全局位置(私有部分) - 现在效果很好!
猜你喜欢
  • 2012-10-09
  • 2021-12-23
  • 2018-05-18
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 2012-06-18
  • 2020-06-16
  • 2021-05-24
相关资源
最近更新 更多