如何捕获子控件下的鼠标移动事件
题
我正在尝试处理特定表单上的鼠标单击事件,如果鼠标光标落在一组坐标之间(比如说一个正方形),该事件应该触发。
我知道,如果我有一个空表单,我可以简单地绑定到 mousemove 事件,然后就可以了。但实际上可能有多达 10 个不同的重叠控件,并且在我的测试应用程序中,仅当光标位于实际表单本身上而不是位于子控件上时才会触发 mousemove 事件。
有谁知道当设计时存在未知数量的子控件时如何处理此事件?
有没有一种简单的单线我可以使用?
解决方案
恕我直言,这里有一些二元的情况:而且没有“单线”。我唯一能看到的解决方案是将无法实现事件的控件获取到一个.NET容器中。
当任何控件获得单击时,正常的预期行为是它将成为表单的活动控件(始终可以通过 this.ActivceControl 访问)。
但是,特别是如果您单击的控件捕获了鼠标,则必须引发事件,因为 .NET 不实现事件“冒泡”(如 WPF 那样)。
处理任何密封对象或其他对象的扩展行为的常用方法是编写扩展方法,我发现为 Control 编写扩展非常容易,但我不知道在这种情况下这是否会对您有帮助。不幸的是我现在不在我的祖国,并且没有 Visual Studio 可以使用。
可以用来确定窗体上的给定点是否落在任何控件的范围内的一种策略是通过“forall of the Forms Control.Collection (this.Controls)”枚举窗体上所有控件的区域(边界)。但是,如果您有重叠的控件,则会遇到多个控件可能包含给定点的问题。
最好的,比尔
其他提示
尝试这个:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AddMouseMoveHandler(this);
}
private void AddMouseMoveHandler(Control c)
{
c.MouseMove += MouseMoveHandler;
if(c.Controls.Count>0)
{
foreach (Control ct in c.Controls)
AddMouseMoveHandler(ct);
}
}
private void MouseMoveHandler(object sender, MouseEventArgs e)
{
lblXY.Text = string.Format("X: {0}, Y:{1}", e.X, e.Y);
}
}
我知道这篇文章已经很老了,但在我看来,最简单的方法是让表单来实现 IMessageFilter
. 。在构造函数中(或在 OnHandleCreated
)你打电话
Application.AddMessageFilter(this);
然后你可以在你的实现中捕获所有窗口的消息 IMessageFilter.PreFilterMessage
.
您可能需要对 WIN32 IsChild 方法使用 P/Invoke
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);
连同表格的 Handle
属性以确保您处理正确的消息。
为什么不直接使用控件的鼠标悬停事件处理程序?
我知道我有点晚了,但今天早些时候我在使用面板作为标题栏时遇到了麻烦。我有一个标签来显示一些文本、一个图片框和一些按钮,所有这些都嵌套在面板中,但无论如何我都需要捕获 MouseMove 事件。
我决定做的是实现一个递归方法处理程序来执行此操作,因为我只有 1 级嵌套控件,当您开始接近荒谬的嵌套级别时,这可能无法很好地扩展。
我是这样做的:
protected virtual void NestedControl_Mousemove(object sender, MouseEventArgs e)
{
Control current = sender as Control;
//you will need to edit this to identify the true parent of your top-level control. As I was writing a custom UserControl, "this" was my title-bar's parent.
if (current.Parent != this)
{
// Reconstruct the args to get a correct X/Y value.
// you can ignore this if you never need to get e.X/e.Y accurately.
MouseEventArgs newArgs = new MouseEventArgs
(
e.Button,
e.Clicks,
e.X + current.Location.X,
e.Y + current.Location.Y,
e.Delta
);
NestedControl_Mousemove(current.Parent, newArgs);
}
else
{
// My "true" MouseMove handler, called at last.
TitlebarMouseMove(current, e);
}
}
//helper method to basically just ensure all the child controls subscribe to the NestedControl_MouseMove event.
protected virtual void AddNestedMouseHandler(Control root, MouseEventHandler nestedHandler)
{
root.MouseMove += new MouseEventHandler(nestedHandler);
if (root.Controls.Count > 0)
foreach (Control c in root.Controls)
AddNestedMouseHandler(c, nestedHandler);
}
然后设置就比较简单了:
定义你的“真正的”处理程序:
protected virtual void TitlebarMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Text = string.Format("({0}, {1})", e.X, e.Y);
}
}
然后设置控件事件订阅者:
//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);
使用起来相对简单,我可以保证它确实有效:)