如何捕获子控件下的鼠标移动事件

发布于 2024-08-10 21:31:14 字数 250 浏览 14 评论 0原文

我正在尝试处理特定表单上的鼠标单击事件,如果鼠标光标落在一组坐标之间(比如说一个正方形),该事件应该触发。

我知道,如果我有一个空表单,我可以简单地绑定到 mousemove 事件,然后就可以了。但实际上可能有多达 10 个不同的重叠控件,并且在我的测试应用程序中,仅当光标位于实际表单本身上而不是位于子控件上时才会触发 mousemove 事件。

有谁知道当设计时存在未知数量的子控件时如何处理此事件?

有没有一种简单的单线我可以使用?

I am trying to handle a mouseclick event on a particular form that should fire if the mouse cursor falls between a set of coordinates - lets say a square.

I understand that if I had an empty form I could simply tie in to the mousemove event and off I go. But in reality there may be up to 10 different overlapping controls and in my test app the mousemove event only fires if the cursor is on the actual form itself and not if its over a child control.

Does anyone know how to handle this event when there are an unknown number of child controls at design time?

Is there an easy one-liner I can use?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

两相知 2024-08-17 21:31:14

试试这个:

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

try this:

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);
    }
}
十秒萌定你 2024-08-17 21:31:14

我知道这篇文章已经很老了,但在我看来,最简单的方法是让表单实现 IMessageFilter。在构造函数中(或在OnHandleCreated中)调用

Application.AddMessageFilter(this);

,然后您可以在IMessageFilter.PreFilterMessage的实现中捕获所有窗口的消息。

您可能需要将 P/Invoke 用于 WIN32 IsChild 方法

[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);

以及表单的 Handle 属性,以确保您处理正确的消息。

I know this post is quite old, but it seems to me that the simplest method would be for the form to implement IMessageFilter. In the constructor (or in OnHandleCreated) you call

Application.AddMessageFilter(this);

and then you can catch the messages of all windows in your implementation of IMessageFilter.PreFilterMessage.

You'd likely need to use P/Invoke for the WIN32 IsChild method

[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);

along with the form's Handle property to ensure that you're handling the right messages.

多彩岁月 2024-08-17 21:31:14

恕我直言,这里有一点二元的情况:并且没有“一行”。我能看到的唯一解决方案是将不实现事件的控件放入实现事件的 .NET 容器中。

当任何控件获得单击时,正常的预期行为是它将成为表单的活动控件(始终可以通过 this.ActivceControl 访问)。

但是,特别是如果您单击的控件捕获了鼠标,则必须引发事件,因为 .NET 不实现事件“冒泡”(如 WPF 那样)。

处理任何密封对象或其他对象的扩展行为的常用方法是编写扩展方法,我发现为 Control 编写扩展非常容易,但我不知道在这种情况下这是否会对您有帮助。不幸的是我现在不在我的祖国,并且没有 Visual Studio 可以使用。

可以用来确定窗体上的给定点是否落在任何控件的范围内的一种策略是通过“forall of the Forms Control.Collection (this.Controls)”枚举窗体上所有控件的区域(边界)。但是,如果您有重叠的控件,则会遇到多个控件可能包含给定点的问题。

最好的,比尔

imho there is a bit of a binary situation here : and there is no "one-liner." the only solution I can see is to get your controls that don't implement events into a .NET container that does.

When any control gets a click, the normal expected behavior is that it will become the Active Control of the Form (which can always be accessed by this.ActivceControl).

But, particulary if the control you clicked captures the mouse, something has got to raise an event since .NET does not implement event "bubbling" (as WPF does).

The usual way to deal with extending behavior of any object that is sealed or whatever is to write an extension method, and I have found writing extensions for Control quite easy, but I don't know if that will help you in this case. Unfortunately I am out of my home country right now, and do not have Visual Studio to play around with.

One strategy you can use to determine if a given Point on a Form falls within the bounds of any Control is to enumerate the areas (Bounds) of all controls on the Form via 'forall of the Forms Control.Collection (this.Controls). But, if you have overlapping Controls, you then have the issue of more than one control possibly containing a given point.

best, Bill

够钟 2024-08-17 21:31:14

为什么不直接使用控件的鼠标悬停事件处理程序?

Why don't you just use the controls' mouseover event handlers?

谁把谁当真 2024-08-17 21:31:14

我知道我有点晚了,但今天早些时候我在使用面板作为标题栏时遇到了麻烦。我有一个标签来显示一些文本、一个图片框和一些按钮,所有这些都嵌套在面板中,但无论如何我都需要捕获 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);

使用相对简单,我可以保证它有效:)

I know I'm a bit late to the punch, but I was having troubles with this earlier today when using a Panel as a title bar. I had a label to display some text, a picturebox and a few buttons all nested within the Panel, but I needed to trap the MouseMove event regardless.

What I decided to do was implement a recursive method handler to do this, as I only had 1 level of nested controls, this may not scale overly well when you start approaching ridiculous levels of nesting.

Here's how I did it:

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

And then to set it up is relatively simple:

Define your "true" handler:

    protected virtual void TitlebarMouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.Text = string.Format("({0}, {1})", e.X, e.Y);
        }
    }

And then set up the controls event subscribers:

//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);

Relatively simple to use, and I can vouch for the fact it works :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文