I'm adding support for mouse wheel movement to a TScrollBox (using the FormMouseWheel procedure) and I need to determine if the mouse is inside the component.
Basically I need to determine if the mouse is inside the TScrollBox so that I then handle the scrolling code accordingly.
Any idea on how to do this?
EDIT: Here's the code (including the answer to this question) as it might help others:
procedure TForm1.FormMouseWheel(Sender: TObject;
Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
var Handled: Boolean);
var
Msg: Cardinal;
Code: Cardinal;
I, ScrollLines:开发者_如何转开发 Integer;
ScrollBoxCursosPos: TPoint;
begin
//position of the mouse cursor related to TScrollBox
ScrollBoxCursosPos := ScrollBox1.ScreenToClient(Mouse.CursorPos);
if (PtInRect(ScrollBox1.ClientRect, ScrollBoxCursosPos)) then
begin
Handled := True;
If ssShift In Shift Then
msg := WM_HSCROLL
Else
msg := WM_VSCROLL;
If WheelDelta < 0 Then
code := SB_LINEDOWN
Else
code := SB_LINEUP;
ScrollLines:= Mouse.WheelScrollLines * 3;
for I:= 1 to ScrollLines do
ScrollBox1.Perform(Msg, Code, 0);
ScrollBox1.Perform(Msg, SB_ENDSCROLL, 0);
end;
end;
Mouse.CursorPos
returns the mouse position in screen coordinates. You can convert this to "client" coordinates, ie coordinates relative to the control, by calling the control's ScreenToClient
method.
So you'll have code something like this:
var
MyPoint : TPoint;
begin
MyPoint := ScrollBox1.ScreenToClient(Mouse.CursorPos);
if PtInRect(ScrollBox1.ClientRect, MyPoint) then
begin
// Mouse is inside the control, do something here
end;
end;
That will let you know if it's inside the control.
From the look of it you're implementing scrolling with the mousewheel? If so don't forget to call SystemParametersInfo
with SPI_GETWHEELSCROLLLINES
or possibly, if it's in your version of Delphi, Mouse.WheelScrollLines
to find out how many lines to scroll per mousewheel increment. What that means to your app probably depends on what you've got in the scrollbox.
If you're planning to also implement middle-click-and-drag scrolling (I'm speculating here, this is well past what you asked about) you might want to get mouse events after the mouse has left the control or form until the user lets go the button, for example. If so, have a look at SetCapture
and ReleaseCapture
and this article. (That article uses those to see if the mouse is over a control (there, a form) although I think the code I wrote above is a better solution to that specific problem - point is they're handy for getting mouse information even when the mouse is not over your form or control.)
(Edit: I just noticed that Delphi 2010's TMouse
has properties that wrap these API calls, WheelScrollLines
and Capture
. I'm not sure how recently they were added - I might just not have noticed them before - but on the assumption they're new-ish and because you don't say what version of Delphi you're using I'm leaving the above text and WinAPI references. If you're using a recent version have a look at the TMouse
documentation.)
I am using the same method to scroll my scrollboxes using the mouse.
This is the event handler for the MouseWheel event of the form. It will scroll horizontally if you press shift key while scrolling:
procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
Msg: Cardinal;
Code: Cardinal;
I, ScrollLines: Integer;
begin
if IsCoordinateOverControl(MousePos, ScrollBox1) then
begin
Handled := True;
If ssShift In Shift Then
Msg := WM_HSCROLL
Else
Msg := WM_VSCROLL;
If WheelDelta < 0 Then
Code := SB_LINEDOWN
Else
Code := SB_LINEUP;
ScrollLines := Mouse.WheelScrollLines * 3;
for I := 1 to ScrollLines do
ScrollBox1.Perform(Msg, Code, 0);
ScrollBox1.Perform(Msg, SB_ENDSCROLL, 0);
end;
end;
You can use this function to check if the screen coordinate of the mouse is over your control:
function IsCoordinateOverControl(screenCoordinate: TPoint; control: TControl): Boolean;
var
p: TPoint;
r: TRect;
begin
Result := False;
p := control.ScreenToClient(screenCoordinate);
r := Rect(0, 0, control.Width, control.Height);
if PtInRect(r, p) then
Result := True;
end;
My Delphi knowledge is a bit rusty, but shouldn't there be MouseEnter, MouseLeave events? A quick google showed this. Does that help you?
精彩评论