如何确定鼠标光标是否在控件内

时间:2009-11-12 11:55:05

标签: delphi

我正在添加对鼠标滚轮移动的支持到TScrollBox(使用FormMouseWheel过程),我需要确定鼠标是否在组件内。

基本上我需要确定鼠标是否在TScrollBox中,以便我随后处理滚动代码。

关于如何做到这一点的任何想法?

编辑:这是代码(包括这个问题的答案),因为它可能会帮助其他人:

   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;

3 个答案:

答案 0 :(得分:22)

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 with SPI_GETWHEELSCROLLLINES或者可能,如果它在您的Delphi版本中,Mouse.WheelScrollLines以找出每个鼠标滚轮增量滚动的行数。这对您的应用程序意味着什么可能取决于您在滚动框中的内容。

如果您计划同时实施中间点击并拖动滚动(我在这里推测,这远远超出您的要求),您可能希望在鼠标离开控件后获取鼠标事件或例如,直到用户放开按钮为止。如果是,请查看SetCaptureReleaseCapture以及this article。 (那篇文章使用那些来查看鼠标是否在控件上(那里,一个表单)虽然我认为我上面编写的代码是解决这个特定问题的更好的解决方案 - 重点是它们对于获取鼠标信息很方便,即使鼠标不在你的表格或控制之上。)

(编辑:我刚注意到Delphi 2010的TMouse具有包含这些API调用的属性,WheelScrollLinesCapture。我不确定它们最近被添加 - 我可能只是之前没有注意到它们 - 但是假设它们是新的,因为你没有说你正在使用的是什么版本的Delphi我将离开上面的文本和WinAPI引用。如果你使用的是最近的版本查看the TMouse documentation。)

答案 1 :(得分:1)

我使用相同的方法使用鼠标滚动滚动框。

这是表单的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;

答案 2 :(得分:0)

我的Delphi知识有点生疏,但是不应该有MouseEnter,MouseLeave事件吗?快速谷歌显示this。这对你有帮助吗?