C# 从每个组件捕获鼠标事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/804374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:51:36  来源:igfitidea点击:

Capturing mouse events from every component

c#winformsmouseevent

提问by Gustavo Cardoso

I have a problem with MouseEvents on my WinForm C# application.

我的 WinForm C# 应用程序上的 MouseEvents 有问题。

I want to get allmouse clicks on my application, but I don't want to put a listener in every child component neither use Windows mouse hook.

我想在我的应用程序上获得所有鼠标点击,但我不想在每个子组件中都放置一个侦听器,也不想使用 Windows 鼠标钩子。

On Flash I could put a listener on Stage to get all the MouseEvents on the movie.

在 Flash 上,我可以在舞台上放置一个监听器来获取电影上的所有 MouseEvents。

Is there such thing on C#? A global MouseListener?

C#上有这种东西吗?全局 MouseListener?



Edit:

编辑:

I create this class from IMessageFilter ans used Application.AddMessageFilter.

我从 IMessageFilter 和使用 Application.AddMessageFilter 创建了这个类。

public class GlobalMouseHandler : IMessageFilter{

    private const int WM_LBUTTONDOWN = 0x201;

    public bool PreFilterMessage(ref Message m){
        if (m.Msg == WM_LBUTTONDOWN) {
            // Do stuffs
        }
        return false;
    }
}

And put this code on the Controls that need listen global clicks:

并将这段代码放在需要监听全局点击的控件上:

GlobalMouseHandler globalClick = new GlobalMouseHandler();
Application.AddMessageFilter(globalClick);

采纳答案by Tim Robinson

One straightforward way to do this is to add a message loop filter by calling Application.AddMessageFilterand writing a class that implements the IMessageFilterinterface.

一种直接的方法是通过调用Application.AddMessageFilter和编写实现IMessageFilter接口的类来添加消息循环过滤器。

Via IMessageFilter.PreFilterMessage, your class gets to see any inputs messages that pass through your application's message loop. PreFilterMessagealso gets to decide whether to pass these messages on to the specific control to which they're destined.

通过IMessageFilter.PreFilterMessage,您的班级可以看到通过您的应用程序的消息循环的任何输入消息。PreFilterMessage还可以决定是否将这些消息传递给它们指定的特定控件。

One piece of complexity that this approach introduces is having to deal with Windows messages, via the Message struct passed to your PreFilterMessagemethod. This means referring to the Win32 documention on WM\_LBUTTONDOWN, WM\_MOUSEMOVE, WM\_LBUTTONUPetc, instead of the conventional MouseDown, MouseMoveand MouseUpevents.

这种方法引入的一个复杂性是必须通过传递给您的PreFilterMessage方法的 Message 结构来处理 Windows 消息。这意味着涉及到对Win32的机制的文档WM\_LBUTTONDOWN, WM\_MOUSEMOVEWM\_LBUTTONUP等等,而不是传统的MouseDownMouseMoveMouseUp事件。

回答by JP Alioto

Take a look at this article. It recursively hoooks all the control events and broadcasts them. You could also override WndProcin your form.

看看这篇文章。它递归地钩住所有控制事件并广播它们。您还可以在表单中覆盖WndProc

回答by Hamish Smith

If you don't want to handle the messages by overriding Form.PreProcessMessage or Form.WndProc then you could subclass Form to hook an event handler to all the MouseClick events from the various controls on the form.
EDIT: forgot to recurse through child controls of controls on the form.

如果您不想通过覆盖 Form.PreProcessMessage 或 Form.WndProc 来处理消息,那么您可以子类化 Form 以将事件处理程序挂接到来自表单上各种控件的所有 MouseClick 事件。
编辑:忘记通过表单上控件的子控件进行递归。

    public class MousePreviewForm : Form
    {
      protected override void OnClosed(EventArgs e)
      {
         UnhookControl(this as Control);
         base.OnClosed(e);
      }

      protected override void OnLoad(EventArgs e)
      {
         base.OnLoad(e);

         HookControl(this as Control);
      }

      private void HookControl(Control controlToHook)
      {
         controlToHook.MouseClick += AllControlsMouseClick;
         foreach (Control ctl in controlToHook.Controls)
         {
            HookControl(ctl);
         }      
      }

      private void UnhookControl(Control controlToUnhook)
      {
         controlToUnhook.MouseClick -= AllControlsMouseClick;
         foreach (Control ctl in controlToUnhook.Controls)
         {
            UnhookControl(ctl);
         }
      }

      void AllControlsMouseClick(object sender, MouseEventArgs e)
      {
         //do clever stuff here...
         throw new NotImplementedException();
      }
   }

Your forms would then need to derive from MousePreviewForm not System.Windows.Forms.Form.

然后您的表单需要从 MousePreviewForm 派生而不是 System.Windows.Forms.Form。

回答by Renjith V

Sample Class

样本类

class CaptureEvents : IMessageFilter
{
    #region IMessageFilter Members
    public delegate void Callback(int message);
    public event Callback MessageReceived;

    IntPtr ownerWindow;
    Hashtable interestedMessages = null;
    CaptureEvents(IntPtr handle, int[] messages)
    {
        ownerWindow = handle;
        for(int c = 0; c < messages.Length ; c++)
        {
            interestedMessages[messages[c]] = 0;
        }
    }
    public bool PreFilterMessage(ref Message m)
    {
        if (m.HWnd == ownerWindow && interestedMessages.ContainsKey(m.Msg))
        {
            MessageReceived(m.Msg);
        }
        return true;
    }

    #endregion
}