Title: TImage And Mouse Wheel - Handling OnMouseWheel For The TImage Delphi Control (And Other TGraphicControl Descendants)
TGraphicControl descendant controls do not receive mouse wheel messages in Delphi. TImage is one such control. Here's how to expose the OnMouseWheel event handler for the TImage Delphi control. What's more: how to handle mouse wheel messages for any TControl descendant.
When the mouse wheel is rotated the OnMouseWheel event will be fired for TControl descendants. If there is no OnMouseWheel event handler, or if the mouse wheel message is not handled in the OnMouseWheel event handler, then an OnMouseWheelUp or OnMouseWheelDown event occurs, depending on the direction the mouse wheel was rotated.
In one of my recent projects, I had a need to handle mouse wheel for a TImage control. Was displaying pages of a PDF document (using Quick PDF Library) and wanted to move to the next / previous page when the user rotates the mouse wheel. Since TImage does not expose mouse wheel message, had to find a solution.
OnMouseWheel for TImage
There are two steps in exposing the OnMouseWheel event (and OnMouseWheelUp, OnMouseWheelDown) for a Timage control. Firstly, using the protected hack you access the OnMouseWheel event. Secondly, you grab the mouse wheel action from the form and send the message to the control under the mouse.
When you scroll the mouse wheel, Windows sends the message to the currently active/focused window. The message is then sent up the parent chain until it reaches the form.
The TForm will be the first control to have the ability to handle mouse wheel actions (before any child controls can react in their OnMouseWheel event handlers).
Therefore, to have TGraphicControl descendants handle mouse wheel messages, grab mouse wheel message in Form's OnMouseWheel event handler then pass it on to the TControl under the mouse.
Here's the code:
type
TImage = class(ExtCtrls.TImage);
TImageForm = class(TForm)
Image1: TImage;
procedure FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure ImageMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
ImageForm: TImageForm;
implementation
{$R *.dfm}
procedure TImageForm.FormCreate(Sender: TObject);
begin
Image1.OnMouseWheel := ImageMouseWheel;
end;
//handles Form OnMouseWheel
procedure TImageForm.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
const
{$J+}
performing : boolean = false;
{$J-}
var
ctrl : TControl;
wc : TWinControl;
begin
Handled := false;
if NOT performing then
begin
wc := FindVCLWindow(MousePos);
if Assigned(wc) then
begin
ctrl := wc.ControlAtPos(wc.ScreenToClient((MousePos)), false, false);
if Assigned(ctrl) then
begin
performing := true;
try
ctrl.Perform(CM_MOUSEWHEEL, WheelDelta, MakeLParam(MousePos.X, MousePos.Y));
finally
performing := false;
end;
Handled := true;
end;
end;
end;
end;
//handles Image OnMouseWheel
procedure TImageForm.ImageMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
//handle Image1 OnMouseWheel here
Caption := IntToStr(WheelDelta);
end;
The above is the code in the TImageForm unit hosting one TImage control (named "Image1").
The
TImage = class(ExtCtrls.TImage);
is a protected hack to be able to get to the OnMouseWheel event handler for Image1.
Using form's OnCreate event you assign the event handing procedure for Image1's OnMouseWheel event.
Finally, in the OnMouseWheel event handler for the form, the mouse wheel message is passed to any TControl under the mouse when the form catches the mouse wheel rotation.