什么是判断鼠标是否在表单上方的最佳方法?
我想出了如何捕获整个表单上的鼠标点击 ,但这种方法不能很好地转换为MouseEnter
和MouseLeave
。 我的表单布局由许多Panels
和TableLayoutPanels
因此没有全面的控件我可以监视事件,显然按钮的MouseLeave
事件并不意味着光标离开了整个表单。 有没有人想出一个解决这个问题的好方法?
正如有人在这里指出的那样,可以使用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; } } }
一个开始的地方是检查ClientRectangle是否包含当前鼠标位置。 因此,例如,在您的MouseMove处理程序上,您可以:
if (ClientRectangle.Contains(e.Location)) { bool mouseIsOverThisControl = true; }
使用合理的间隔(可能为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; } }
我发现了一些接近我想要的答案,但我做了不同的事情。 我想检测鼠标是否离开了表单区域(包括标题栏),这对我有用:
在表单构造函数中,我添加了一个计时器:
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; } }
在Form和Form控件上执行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"); } }
如果表单上有许多对象,这可能会变得乏味