【问题标题】:What's the best way to tell if the mouse is over a form or not?判断鼠标是否在表单上的最佳方法是什么?
【发布时间】:2011-02-21 21:57:09
【问题描述】:

我在整个表单中找到了how to capture mouse clicks,但这种方法不能很好地转换为MouseEnterMouseLeave。我的表单布局由许多PanelsTableLayoutPanels 组成,因此没有可以监视事件的包罗万象的控件,显然按钮的MouseLeave 事件并不意味着光标离开了整个表单。有没有人想出一个解决这个问题的好方法?

【问题讨论】:

    标签: c# .net winforms mouseover


    【解决方案1】:

    首先要检查ClientRectangle 是否包含当前鼠标位置。因此,例如,在您的 MouseMove 处理程序上,您可以:

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

    【讨论】:

    • 这对整个表格都有效吗?我可以看到这将如何捕获MouseEnter 事件,但是当鼠标离开表单时,它会停止调用MouseMove 事件,所以它不会检查它是否离开了表单,不是吗?
    • 什么时候需要知道鼠标在表单上?
    • 整个表单就像一个巨大的按钮。 (这是来电的通知。)所以当用户将鼠标悬停在表单上时,我希望它亮起,表示按下它会接听电话。
    【解决方案2】:

    正如有人指出的here,可以使用 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;
            }
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      以合理的间隔(可能是 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() 是表单上 Timer 的 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 调用。只是不要这样做。永远。
      【解决方案4】:

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

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

      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;
          }
      }
      

      【讨论】:

        【解决方案5】:

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

        一个例子是

            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");
                }
            }
        

        如果表单上有很多对象,这可能会变得乏味

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-31
          • 1970-01-01
          • 2010-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多