Как определить, находится ли курсор мыши внутри элемента управления

Я добавляю поддержку перемещения колеса мыши к TScrollBox (используя процедуру FormMouseWheel), и мне нужно определить, находится ли мышь внутри компонента.

В основном мне нужно определить, находится ли мышь внутри TScrollBox, чтобы затем обрабатывать код прокрутки.

Любая идея о том, как это сделать?

EDIT: здесь код (включая ответ на этот вопрос), поскольку он может помочь другим:

   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;

Ответ 1

Mouse.CursorPos возвращает положение мыши в координатах экрана. Вы можете преобразовать это в "клиентские" координаты, то есть в координаты относительно элемента управления, вызвав метод ScreenToClient.

Итак, у вас будет код примерно так:

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;

Это даст вам знать, находится ли внутри элемента управления.

По внешнему виду вы используете прокрутку с колесом мыши? Если это так, не забудьте вызвать SystemParametersInfo с SPI_GETWHEELSCROLLLINES или, возможно, если это в вашей версии Delphi, Mouse.WheelScrollLines, чтобы узнать, сколько строк прокручивается на шаг мыши. Что это значит для вашего приложения, вероятно, зависит от того, что у вас есть в прокрутке.

Если вы планируете также осуществлять прокрутку по середине щелчка и перетаскивания (я размышляю здесь, это далеко не так, как вы просили), вы можете захотеть получить события мыши после того, как мышь оставила элемент управления или пока пользователь не запустит кнопку, например. Если да, взгляните на SetCapture и ReleaseCapture и в этой статье. (В этой статье мы видим, что мышь находится над элементом управления (там, форма), хотя я думаю, что код, который я написал выше, является лучшим решением для этой конкретной проблемы, так как они удобны для получения информации о мыши, даже если мышь не над вашей формой или контролем.)

(Edit: Я только заметил, что Delphi 2010 TMouse имеет свойства, которые обертывают эти вызовы API, WheelScrollLines и Capture. Я не уверен, как недавно они были добавлены - я бы просто не заметил их раньше, - но, исходя из предположения, они новы и потому что вы не говорите, какую версию Delphi вы используете. Я оставляю приведенный выше текст и ссылки на WinAPI. Если вы используете недавнюю версию, посмотрите документация TMouse.)

Ответ 2

Я использую тот же метод для прокрутки моих scrollboxes с помощью мыши.

Это обработчик событий для события MouseWheel формы. Он будет прокручиваться по горизонтали, если вы нажимаете клавишу Shift при прокрутке:

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;

Вы можете использовать эту функцию, чтобы проверить, находится ли координата экрана мыши над вашим контролем:

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;

Ответ 3

Знание My Delphi немного ржавое, но не должно быть событий MouseEnter, MouseLeave? Быстрый google показал этот. Это поможет вам?