首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使MouseWheel事件从子事件传递到父事件

使MouseWheel事件从子事件传递到父事件
EN

Stack Overflow用户
提问于 2015-10-14 15:43:45
回答 4查看 3.6K关注 0票数 5

我有一个Panel,其中AutoScroll是真的。此面板包含许多较小的面板,以填充所有可用的空间,如瓷砖。当有太多的子面板显示,我得到垂直滚动条,如预期。

这些"tiles“中的每一个都有一些事件处理程序绑定到它们,以处理MouseDown / MouseUp / MouseMove,因为它们可以被拖来拖去。

我遇到的问题是,鼠标滚轮滚动不能在父面板上工作,因为它不会有焦点。我不能给它焦点,因为很可能,我会滚动,同时移动一个子面板,它将有焦点,即使这样,这将需要解决办法,因为面板不喜欢焦点。

我一直试图(失败)找到一种方法,只将鼠标轮事件从子级传播到父级。

我在Winforms中读到过,如果一个控件不能处理鼠标事件,它会将它泡到该控件的父控件,然后再泡到该控件的父控件,以此类推,直到找到合适的处理程序。

考虑到这一点,我认为最好的解决方案是使用WndProc覆盖子面板上所有与滚动相关的事件,并将它们传递给父程序,同时保持所有其他事件的完整,但必须承认,这不是我的强项,我迷路了。

我尝试过其他一些解决方案,比如让所有鼠标事件都看不到子面板,但正如您可能已经猜到的那样,这是不好的。我读过关于实现消息过滤器的文章,但是我不明白。

下面的代码将为您提供一个非常基本的面板及其子程序示例:

代码语言:javascript
复制
private void Form1_Load(object sender, EventArgs e)
{
    Height = 600;
    Width = 300;

    Color[] colors = new Color[]{ Color.PowderBlue, Color.PeachPuff };

    Panel panel = new Panel()
    {
        Height = this.ClientSize.Height - 20,
        Width = 200,
        Top = 10,
        Left = 10,
        BackColor = Color.White,
        BorderStyle = BorderStyle.FixedSingle,
        AutoScroll = true
    };

    for (int i = 0; i < 10; i++)
    {
        Panel subPanel = new Panel()
        {
            Name = @"SubPanel " + i.ToString(),
            Height = 100,
            Width = panel.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 2,
            BackColor = colors[i % 2],
            Top = i * 100
        };
        subPanel.MouseClick += subPanel_MouseClick;
        panel.Controls.Add(subPanel);
    }

    Controls.Add(panel);
}

void subPanel_MouseClick(object sender, MouseEventArgs e)
{
    Panel panel = sender as Panel;
    Text = panel.Name;
}

下面是我在定制面板中重写WndProc的尝试:

代码语言:javascript
复制
class NoScrollPanel : Panel
{
    private const int WM_HSCROLL = 0x114;
    private const int WM_VSCROLL = 0x115;
    private const int MOUSEWHEEL = 0x020A;
    private const int KEYDOWN = 0x0100;

    protected override void WndProc(ref Message m)
    {
        if ((m.HWnd == Handle) && (m.Msg == MOUSEWHEEL || m.Msg == WM_VSCROLL || (m.Msg == KEYDOWN && (m.WParam == (IntPtr)40 || m.WParam == (IntPtr)35))))
        {
            PostMessage(Parent.Handle, m.Msg, m.WParam, m.LParam);
        }
        else
        {
            base.WndProc(ref m);
        }
    }

    [DllImport("User32.dll")]
    private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}

任何帮助或替代方法都是最受欢迎的。谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-10-15 07:26:22

所有的功劳都归于汉斯·帕桑特(又一次),来自他建议的那条线:https://stackoverflow.com/a/3562449/17034

允许包含的面板获得焦点效果很好。对于上述类中的演示代码,只需将其用于包含面板即可。在必要的时候,我不得不对我的项目做一些调整,让它成为焦点,但这与火箭科学相去甚远。

再次感谢。

票数 2
EN

Stack Overflow用户

发布于 2019-07-22 10:38:31

在我身边@a的解决方案不起作用,也许是不同的环境。目前,我的问题没有直接、清晰的答案,所以我尝试将其他专业人士的几种想法结合起来,并取得成功。

在我的当前项目中,我在面板中包含了一些输入控件。我创建了一个ComboBox的子类,并覆盖它的WndProc,从而使鼠标轮滚动面板,而不是滚动ComboBox项:

代码语言:javascript
复制
public class ComboBoxWithParentMouseWheel : ComboBox
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

    const int WM_MOUSEWHEEL = 0x020A;

    //thanks to a-clymer's solution
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEWHEEL)
        {
            //directly send the message to parent without processing it
            //according to https://stackoverflow.com/a/19618100
            SendMessage(this.Parent.Handle, m.Msg, m.WParam, m.LParam);
            m.Result = IntPtr.Zero;
        }else base.WndProc(ref m);
    }
}
票数 6
EN

Stack Overflow用户

发布于 2017-11-07 01:17:30

这些解决方案我都找不到了。我和您一样,正在重写WndProc fxn。终于找到解决办法了!我注意到,如果保存我的TextBox的容器在焦点上,那么滚动条就能工作,只是当TextBox处于焦点时就不行了。

我不需要更改事件的透明度,我需要将事件发送到另一个Control句柄!(现在看起来很简单,但我已经想了好几天了!)

代码语言:javascript
复制
internal class myTextBox : TextBox
{
    const int WM_MOUSEWHEEL = 0x020A;

    protected override void WndProc(ref Message m)
    {

        if (m.Msg == WM_MOUSEWHEEL)
            m.HWnd = this.Parent.Handle; // Change the Handle of the message

        base.WndProc(ref m);
    }
}

在我所有的谷歌搜索中,我没有看到任何关于这个方法的提及,如果有什么理由不这样做,我希望有人会回复。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33129854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档