tags:

views:

276

answers:

2

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;
A: 

My Delphi knowledge is a bit rusty, but shouldn't there be MouseEnter, MouseLeave events? A quick google showed this. Does that help you?

Thorsten Dittmar
The procedure I need to use is FormMouseWheel because I need to respond to mouse wheel movements, not enter and leave events.
smartins
Yes, but you could use these events to know whether the mouse enters or leaves (=> is inside) the scrollbox.
Thorsten Dittmar
The problem with mouseenter/leave way is that those events are fired for the child controls too. So David M's solution gets my vote.
utku_karatas
+5  A: 

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.)

David M
Perfect, I've reached the ScreenToClient part already but wasn't sure I was getting the correct value. Thanks for the help.
smartins