2009-11-12 98 views
11

我正在向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; 

回答

21

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找出多少行滚动每个鼠标滚轮增量。这对您的应用意味着什么可能取决于您在滚动框中的内容。

如果您打算实现中间点击并拖动滚动(我在这里进行推测,这完全超出了您所问的范围),您可能想在鼠标离开控件后获得鼠标事件或者形成,直到用户放开按钮为止。如果是这样,看看SetCaptureReleaseCapturethis article。 (该文章使用这些来查看鼠标是否超过了控件(那里,一个表单),尽管我认为我上面写的代码是针对该特定问题的更好的解决方案 - 要点是它们在获取鼠标信息时非常方便,即使在鼠标是不是在你的窗体或控件)

(编辑:我只注意到德尔福2010中的TMouse有包装这些API调用,WheelScrollLinesCapture属性我不知道他们是如何最近增加了 - 我可能只是之前没有注意到它们 - 但是假设它们是新的,因为你没有说你使用的是什么版本的Delphi,我将离开上面的文本和WinAPI引用。如果你使用的是最新版本看看the TMouse documentation。)

+0

完美,我已经到达ScreenToClient部分,但不知道我是否获得了正确的值。谢谢您的帮助。 – smartins 2009-11-12 15:42:25

0

我的德尔福知识是有点生疏,但不应该有的MouseEnter,鼠标离开事件?快速谷歌显示this。这对你有帮助吗?

+0

我需要使用的程序FormMouseWheel是因为我需要响应鼠标轮的移动,而不是进入和离开事件。 – smartins 2009-11-12 12:17:14

+0

是的,但是您可以使用这些事件来了解鼠标是否进入或离开(=>在里面)滚动框。 – 2009-11-12 12:26:22

+0

mouseenter/leave方式的问题在于,这些事件也是针对子控件触发的。所以David M的解决方案得到了我的投票。 – 2009-11-12 15:23:17

1

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

这是表单的MouseWheel事件的事件处理程序。

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; 

您可以使用此功能检查,如果鼠标的屏幕坐标是在你的控制:如果您按下Shift键的同时滚动它会水平滚动

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; 
相关问题