I have a custom component witht the following events
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;
I assign them to a TImage whose parent is TPanel whos parent is 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;
The component compiles and bulds just fine. The application with this component also compiles and runs jus fine. If I assign an OnClick event, it works. All other events, if I assign them and try to run the app, i get an error saying the event doesn't exist
Anyone know why that is?
The event in Delphi is a method pointer. A method pointer is basically two pointers, one points to the method you assign to the event, and the other points to the live instance (object) you assign.
I think you expect the event in your inner object follows the events assigned to your outer object, and that will not happen automatically.
When you assign it, you're doing pointer assignments. So to take an example, your line
img.OnDblClick:= fOnImageDblClick;
Performs a pointer assignment with the value fOnImageDblClick
have at the time. If it is nil
, img.OnDblClick
will be nil
from now. If it points to Form1.MyComponentImageClick
at the time, img.OnDblClick
will point to the same method on the same object from now, but, if you later change where fOnImageDblClick points, the imgOnDblClick will not follow... it will remains pointing to the same old address. If you want it to change, you have to make that change by code also.
If you want that to happen, you can do that in a event setter in the outer class.
First, declare your events like this:
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;
If your Img
inner object exists all the time, you don't need the FOnImageDblClick
variable, you can write also a getter for the property and take the value directly from the inner object, like this:
function TMyClass.GetOnImageDblClick: TNotifyEvent;
begin
Result := Img.OnDblClick;
end;