如何检测鼠标离开窗体?

6

我有一个包含很多控件的表单,我该如何检测鼠标离开表单的事件?我尝试为每个控件和表单都绑定MouseLeave事件,但这并不起作用,因为当鼠标经过控件时,这些事件会一直触发。有没有一种真正有效的方法?


你需要监听表单本身的mouseleave事件。 - korona
Korona,你的方法不起作用,因为如果鼠标通过被控件覆盖的区域离开表单,form_mouseLeave 将不会触发。 - AngryHacker
这一切都很好,但是当有人使用触摸屏电脑运行您的应用程序时,鼠标从未进入或离开任何东西,会发生什么呢?虽然我认为这样做可以增加视觉效果,但我强烈建议不要将其用于任何真正的应用功能。 - Orion Edwards
或只能使用键盘 (WCAG - http://www.w3.org/TR/2008/WD-UNDERSTANDING-WCAG20-20081103/keyboard-operation-keyboard-operable.html) - StingyJack
很好的输入,但这不应该是评论而不是答案吗? - hrh
显示剩余3条评论
4个回答

7
我知道的唯一可靠的方法是使用计时器。以下是一个示例代码,用于在鼠标悬停时调整不透明度:
  public partial class Form1 : Form {
    Timer timer1 = new Timer();
    public Form1() {
      InitializeComponent();
      this.Opacity = 0.10;
      timer1.Tick += new EventHandler(timer1_Tick);
      timer1.Interval = 200;
      timer1.Enabled = true;
    }

    void timer1_Tick(object sender, EventArgs e) {
      Point pos = Control.MousePosition;
      bool inForm = pos.X >= Left && pos.Y >= Top && pos.X < Right && pos.Y < Bottom;
      this.Opacity = inForm ? 0.99 : 0.10;
    }
  }

3
尽管这种方法不太优美,但我同意这可能是唯一可靠的方法。 - Kevin

4

请注意:

  • 表单中所有控件的MouseLeave事件
  • 表单的MouseLeave事件

只需将您的监听器链接到一个函数,该函数检查光标是否在表单客户端区域内。

尝试以下代码:

    protected override void OnControlAdded(ControlEventArgs e)
    {
        SubscribeEvents(e.Control);
        base.OnControlAdded(e);
    }

    protected override void OnControlRemoved(ControlEventArgs e)
    {
        UnsubscribeEvents(e.Control);
        base.OnControlRemoved(e);
    }

    private void SubscribeEvents(Control control)
    {
        control.MouseLeave += new EventHandler(control_MouseLeave);
        control.ControlAdded += new ControlEventHandler(control_ControlAdded);
        control.ControlRemoved += new ControlEventHandler(control_ControlRemoved);

        foreach (Control innerControl in control.Controls)
        {
            SubscribeEvents(innerControl);
        }
    }

    private void UnsubscribeEvents(Control control)
    {
        control.MouseLeave -= new EventHandler(control_MouseLeave);
        control.ControlAdded -= new ControlEventHandler(control_ControlAdded);
        control.ControlRemoved -= new ControlEventHandler(control_ControlRemoved);

        foreach (Control innerControl in control.Controls)
        {
            UnsubscribeEvents(innerControl);
        }
    }

    private void control_ControlAdded(object sender, ControlEventArgs e)
    {
        SubscribeEvents(e.Control);
    }

    private void control_ControlRemoved(object sender, ControlEventArgs e)
    {
        UnsubscribeEvents(e.Control);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        CheckMouseLeave();
        base.OnMouseLeave(e);
    }

    private void control_MouseLeave(object sender, EventArgs e)
    {
        CheckMouseLeave();
    }

    private void CheckMouseLeave()
    {
        Point pt = PointToClient(Cursor.Position);

        if (ClientRectangle.Contains(pt) == false)
        {
            OnMouseLeftFrom();
        }
    }

    private void OnMouseLeftFrom()
    {
        Console.WriteLine("Mouse left the form");
    }

1
不错,我学到了新东西:ClientRectangle.Contains(pt)。谢谢。+1 - Stefan

2

参考 aygunes.myopenid.com 的答案,我用 Vb.Net 编写了这个版本,递归添加 MouseLeaveHandlers 到窗体上的所有控件,然后使用漂亮的 Clientrectangle.Contains(pt) 来检查鼠标光标是否在窗体内或外。效果非常好。感谢 aygunes.myopenid.com。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    AddMouseLeaveHandlers()
End Sub
Sub AddMouseLeaveHandlers()
    For Each c As Control In Me.Controls
        HookItUp(c)
    Next
    AddHandler Me.MouseLeave, AddressOf CheckMouseLeave
End Sub
Sub HookItUp(ByVal c As Control)        
    AddHandler c.MouseLeave, AddressOf CheckMouseLeave
    If c.HasChildren Then
        For Each f As Control In c.Controls
            HookItUp(f)
        Next
    End If
End Sub
Private Sub CheckMouseLeave(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim pt As Point = PointToClient(Cursor.Position)
    If ClientRectangle.Contains(pt) = False Then
        MsgBox("Mouse left form")
    End If
End Sub

1
将此放入计时器中:
If PointToClient(MousePosition).X < Me.Size.Width AndAlso PointToClient(MousePosition).X > -1 AndAlso PointToClient(MousePosition).Y < Me.Size.Height AndAlso PointToClient(MousePosition).Y > -1 Then
    'Mouse is inside the form
Else
    'Mouse is outside of form
End If

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接