Windows Forms:捕获鼠标滚轮事件

6
我有一个Windows表单(在C#.NET中工作)。
该表单顶部有几个面板,底部有一些ComboBoxes和DataGridViews。
我想在顶部面板上使用滚动事件,但是如果选择例如ComboBox,则会失去焦点。面板包含各种其他控件。
当鼠标位于任何面板上时,如何始终接收鼠标滚轮事件? 到目前为止,我尝试使用MouseEnter / MouseEnter事件,但没有成功。
2个回答

13

根据您的描述,你想要复制类似于Microsoft Outlook的功能,允许您在不需要实际点击控件即可使用鼠标滚轮。

这是一个相对高级的问题,需要实现包含窗体的 IMessageFilter 接口,查找 WM_MOUSEWHEEL 事件并将其定向到鼠标悬停的控件。

下面是一个示例(来自这里):

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1 {
  public partial class Form1 : Form, IMessageFilter {
    public Form1() {
      InitializeComponent();
      Application.AddMessageFilter(this);
    }

    public bool PreFilterMessage(ref Message m) {
      if (m.Msg == 0x20a) {
        // WM_MOUSEWHEEL, find the control at screen position m.LParam
        Point pos = new Point(m.LParam.ToInt32());
        IntPtr hWnd = WindowFromPoint(pos);
        if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) {
          SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
          return true;
        }
      }
      return false;
    }

    // P/Invoke declarations
    [DllImport("user32.dll")]
    private static extern IntPtr WindowFromPoint(Point pt);
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
  }
}
请注意,此代码对应用程序中的所有表单都是活动的,而不仅仅是主要表单。

嘿,那是我的代码!我不太确定是否需要归属权,但应该需要。 - Hans Passant
@Hans Passant,@Jon Grant 谢谢... 顺便问一下:我能让它只在特定控件上工作吗?例如,如果没有焦点,则不滚动组合框? - n0ter
1
刚刚实现了类似的东西,但是加了一个额外的测试:"Control.FromHandle(hWnd).FindForm() == this",以确保它只适用于同一窗体上的控件的消息。 - Jules
谢谢你提供这么棒的代码!我都明白了,就是不理解这个测试:hWnd != m.HWnd。它的目的是什么? - Kevin Vuilleumier
@KevinVuilleumier hWnd 包含鼠标位置下控件的窗口句柄。它正在检查 WM_MOUSEWHEEL 消息是否已经发送到控件。如果没有,那么我们将消息发送给它(如果是,则我们不需要做任何事情)。 - Jon Grant
显示剩余4条评论

0

每个控件都有一个鼠标滚轮事件,该事件在控件获得焦点时发生。

查看此处以获取更多信息:Control.MouseWheel Event


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接