It turns out that the only problem is that the OnMouseWheel property is not published or in the TEdit help. If it was, I would have learned about it long ago. (It is listed in the TWinControl help as a protected event.)
Basic Processing
The basic procedure is
message WM_MOUSEWHEEL -> WMMouseWheel() -> MouseWheelHandler() -> Form.MouseWheelHandler() OR Perform(CM_MOUSEWHEEL,..) |
message CM_MOUSEWHEEL -> CMMouseWheel() -> if DoMouseWheel() else Parent.Perform(CM_MOUSEWHEEL) |
function DoMouseWheel() (pseudo code - please see original)
if Assigned(FOnMouseWheel) then
FOnMouseWheel(Self, Shift, WheelDelta, MousePos, Result);
if result = false then begin
recursively calls
if WheelDelta < 0
then DoMouseWheelDown
else DoMouseWheelUp
end;
end;
|
(from windows.pas)
const
{$EXTERNALSYM WHEEL_DELTA}
WHEEL_DELTA = 120; { Value for rolling one detent }
(from messages.pas)
TWMMouseWheel = packed record
Msg: Cardinal;
Keys: SmallInt;
WheelDelta: SmallInt;
case Integer of
0: (
XPos: Smallint;
YPos: Smallint);
1: (
Pos: TSmallPoint;
Result: Longint);
end;
(from Controls.pas)
TCMMouseWheel = record // these values are set in
Msg: Cardinal; // TWinControl.WndProc(var Message: TMessage);
ShiftState: TShiftState; // just before MouseWheelHandler() is called
Unused: Byte;
WheelDelta: SmallInt;
case Integer of
0: (
XPos: Smallint;
YPos: Smallint);
1: (
Pos: TSmallPoint;
Result: Longint);
end;
TMouseWheelEvent = procedure(Sender: TObject; Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint; var Handled: Boolean) of object;
TMouseWheelUpDownEvent = procedure(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean) of object;
TWinControl = class(TControl)
private
procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL;
protected
function DoMouseWheel (Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; dynamic;
function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; dynamic;
function DoMouseWheelUp (Shift: TShiftState; MousePos: TPoint): Boolean; dynamic;
property WheelAccumulator: Integer read FWheelAccumulator write FWheelAccumulator;
property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel write FOnMouseWheel;
property OnMouseWheelDown: TMouseWheelUpDownEvent read FOnMouseWheelDown write FOnMouseWheelDown;
property OnMouseWheelUp: TMouseWheelUpDownEvent read FOnMouseWheelUp write FOnMouseWheelUp;
public
procedure MouseWheelHandler(var Message: TMessage); dynamic;
end;
|
ReadOnly
Code Example
protected
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean; override;
function TmcNumberEdit.DoMouseWheel(Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint): Boolean;
begin
if ReadOnly or FDisableMouseWheel then begin // disable this increment control
result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
exit;
end;
// the WheelDelta on my system is 120
// defined in C:\Program Files\Borland\Delphi5\Source\Rtl\Win\windows.pas
// "WheelDelta/WHEEL_DELTA" allows windows acceleration
// if WheelDelta < 0 then the wheel is rolling in the other direction
Increment(WheelDelta div WHEEL_DELTA, Shift); // this processes the wheel event
result := true; // without this, the routine is called twice
end;
|
In theory, WheelDelta can be any integer multiple of 120 (one click of the mouse wheel). Perhaps this allows windows to accelerate the counts based on speed. The default handler assumes that this is possible and repeats the inner loop an appropriate number of times. My code (above) assumes that it will always represent plus or minus a single step.
Author: Robert Clemenzi - clemenzi@cpcug.org