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