Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if the mouse cursor is inside a control

Tags:

delphi

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;
like image 985
smartins Avatar asked Nov 12 '09 11:11

smartins


2 Answers

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

like image 54
David Avatar answered Oct 17 '22 03:10

David


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;
like image 24
Hüseyin Yağlı Avatar answered Oct 17 '22 04:10

Hüseyin Yağlı