如何最好地判断鼠标是否悬停在表单上?

5

我已经想出了如何捕捉整个表单上的鼠标点击,但这种方法对于MouseEnterMouseLeave不太适用。我的表单布局由许多PanelsTableLayoutPanels组成,因此没有一个可以监视事件的全包含控件,显然,对于按钮的MouseLeave事件并不意味着光标离开了整个表单。有没有人想出了一个好的方法来解决这个问题?

5个回答

3

一个开始的方法是检查 ClientRectangle 是否包含当前鼠标位置。例如,在你的 MouseMove 处理程序中,你可以这样写:

if (ClientRectangle.Contains(e.Location))
{
    bool mouseIsOverThisControl = true;
}

这对整个表单有效吗?我可以看到它如何捕获MouseEnter事件,但是当鼠标离开表单时,它停止调用MouseMove事件,因此它不会检查它是否已经离开表单,对吧? - dlras2
你需要知道鼠标何时悬停在你的表单上吗? - bentsai
整个表单就像一个巨大的按钮。(这是一个来电通知。)因此,当用户将鼠标悬停在表单上时,我希望它会亮起来,表示按下它将接听电话。 - dlras2

1

我找到了一些与我想要的接近的答案,但最终我做了一些不同的事情。我想检测鼠标是否离开了表单区域(包括标题栏),这对我有用:

在表单构造函数中,我添加了一个计时器:

time.Interval = 250;
time.Tick += time_Tick;
time.Start();

然后在 `tick` 方法中,我执行以下操作:
void time_Tick(object sender, EventArgs e)
{
    switch (RectangleToScreen(Bounds).Contains(PointToScreen(Cursor.Position))) {
        case true:
            if (Opacity != .9999D)
                Opacity = .9999D;
            break;
        case false:
            if (Opacity != .5D)
                Opacity = .5D;
            break;
    }
}

0

在表单中添加一个合理的间隔计时器(可能是50毫秒)。在Tick事件处理程序中使用以下代码来检查鼠标是否悬停在表单上:

// Check if mouse is currently over the form
    bool temp_mof = ClientRectangle.Contains(
       Form.MousePosition.X - Location.X,
       Form.MousePosition.Y - Location.Y);

编辑:这里有一个更完整的解决方案,可以检测鼠标是否悬停在表单上并且按钮已被点击。 timer1Tick() 是表单上计时器的 Tick 事件处理程序。没有必要为表单上的其他控件添加额外的事件处理程序。这将使您的表单成为“一个巨大的按钮” :)

bool m_mouse_over_form = false;
// Assume the left button is down at onset
bool m_left_button_down = true;

void timer1Tick (object sender, EventArgs e)
{
   // Check if mouse is currently over the form
   bool temp_mof = ClientRectangle.Contains(
      Form.MousePosition.X - Location.X,
      Form.MousePosition.Y - Location.Y);

   // were we already over the form before this tick?
   if (temp_mof && m_mouse_over_form)
   {
       // we need to detect the mouse down and up to avoid
       // repeated calls if the mouse button is held down for more
       // than our Tick interval

       // was the mouse button up prior to now?
       if (!m_left_button_down)
       {
           // is the button down now?
           m_left_button_down = (MouseButtons == MouseButtons.Left);

           if (m_left_button_down)
           {
               // the button was down and has now been released
               LeftButtonClickHandler();
           }
           else
           {
               // do nothing, the button has not been release yet
           }
       }
       else
       {
           // update the button state
           m_left_button_down = (MouseButtons == MouseButtons.Left);
       }
   }
   else if (temp_mof)
   {
       // the mouse just entered the form

       m_mouse_over_form = true;

       // set the initial state of the left button
       m_left_button_down = MouseButtons == MouseButtons.Left);
   }
   else
   {
       // the mouse is not currently over the form
       m_mouse_over_form = false;
       m_left_button_down = true;
   }
}

-1:请不要这样做。SlavaGu给出了一个非常好的答案..如果你必须这样做,请探索Api调用。但永远不要这样做。 - Rusty

0
正如有人在这里指出的那样,可以使用SetWindowsHookEx()或将MouseMove事件连接到窗体中的所有控件。后者对我来说很有效。唯一的缺点是,如果您在运行时添加/删除控件,则可能需要另一种解决方案。
using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsForms_MouseEvents
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            MouseMove += OnMouseMove;
            MouseLeave += OnMouseLeave;

            HookMouseMove(this.Controls);
        }

        private void HookMouseMove(Control.ControlCollection ctls)
        {
            foreach (Control ctl in ctls)
            {
                ctl.MouseMove += OnMouseMove;
                HookMouseMove(ctl.Controls);
            }
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            BackColor = Color.Plum;

            Control ctl = sender as Control;
            if (ctl != null)
            {
                // Map mouse coordinate to form
                Point loc = this.PointToClient(ctl.PointToScreen(e.Location));
                Console.WriteLine("Mouse at {0},{1}", loc.X, loc.Y);
            }
        }

        private void OnMouseLeave(object sender, EventArgs e)
        {
            BackColor = Color.Gray;
        }

    }
}

0

在表单和表单控件上执行鼠标进入和鼠标离开事件;使用布尔值确定鼠标是进入还是离开。

示例:

    private static bool mouseEnteredForm

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        mouseEnteredForm = true;
        Form.MouseLeave += Form1_MouseLeave;
        CheckMouseLocation();
    }

    private void Form1_MouseLeave(object sender, MouseEventArgs e)
    {
        mouseEnteredForm = false
        CheckMouseLocation();
    }

    private static void CheckMouseLocation()
    {
        if(!mouseOverForm)
        {
            MessageBox.Show("Mouse Not Over Form!);
        }
        else if(mouseOverForm) //else if is optional. You could also use else in this case. I used else if for the sake of the example.
        {
            MessageBox.Show("Mouse Is Over Form");
        }
    }

如果表单上有许多对象,这可能会变得很繁琐。


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