4

WinForms GroupBox 控件不支持 MouseMove(或至少不始终如一),我不明白为什么。

由于它来自 Control,它确实有一个 MouseMove 事件,但 GroupBox 用 明确地重新引入它Browsable(false),因此它没有显示在属性网格中。您可以在运行时挂钩 MouseMove 事件,有时它可以工作——只要 FlatStyle 保留在 Standard。如果 GroupBox 的 FlatStyle 设置为 System,则根本不会触发 MouseMove 事件。

反射器没有给我任何线索。GroupBox 构造函数似乎没有设置任何奇怪的控件样式,并且 GroupBox 没有做任何愚蠢的事情,例如覆盖 MouseMove 并且无法调用 base.

这似乎也是 WinForms 特定的限制,因为 Delphi 组框支持 OnMouseMove 就好了。 更正:与 Delphi 的比较无效。Delphi 组合框实际上并不是标准的 BM_GROUPBOX 控件;它们只是被画成看起来像组框,而实际上并没有继承像这样的奇怪的组框行为。所以这很可能是 Windows 组框控件的一个限制,尽管我还没有在任何地方看到它的文档。

为什么 WinForms GroupBox 不支持 MouseMove?

4

4 回答 4

5

根据这个线程,标准 Windows 组框(即,具有 BS_GROUPBOX 样式的 BUTTON 控件)似乎返回 HTTRANSPARENT 以响应 WM_NCHITTEST。由于控件声称是透明的,Windows 将鼠标移动事件发送到其父窗口。

该线程确认,如果您自己处理 WM_NCHITTEST 并返回 HTCLIENT,那么 groupbox 将获得鼠标移动事件。他们正在使用 MFC,但它可能也适用于 WinForms。

不清楚的是为什么Windows 默认返回 HTTRANSPARENT,但至少该问题已得到独立确认。

于 2010-01-01T17:04:45.027 回答
2

您可以使用 Reflector 看到这一点,关键属性是 CreateParams 和内部 OwnerDraw 属性。GroupBox 通常在 OwnerDraw = true 的情况下运行,除非您设置 FlatStyle = System。然后你会得到一个老式的 Windows 组框,一个类名为 BUTTON 的窗口打开了 BS_GROUPBOX 样式位。

如果您使用 Spy++ 查看一下,您会发现该控件根本没有收到任何鼠标消息。不知道为什么会这样,SDK 文档没有提到它。我猜这可以追溯到 Windows 2.x,每个周期都很重要。But it does explain why the MouseMove event is hidden, it cannot fire when the System style is selected. 单击和向上/向下相同。FlatStyle 属性设置器还通过关闭 Control.UserMouse 控件样式来真正确定它。

无论如何,如果您想要鼠标消息,则需要避免使用 System 样式。

于 2009-11-10T20:45:41.190 回答
1

我注意到某些控件的许多事件无法通过 VS 中的事件选项卡(在属性下)访问。您可以在父表单的设计器中手动分配事件处理程序InitializeComponents()

this.groupBox1.MouseMove += new MouseEventHandler(this.groupBox1_MouseMove);

这将触发以下方法:

private void groupBox1_MouseMove(object sender, MouseEventArgs e)
{
    //doodle the stuff you want to happen after the trigger here
};
于 2018-01-12T11:22:45.870 回答
0

组框是一个静态控件,其中包含其他控件。如果布局正确,它纯粹是为了将事物“组合”在一起以使用户界面直观。因此,您可以代表 GroupBox 使用的事件很少。

您可以创建一个从 GroupBox 继承的新类并将其子类化以拦截鼠标移动事件。我以前使用过一个非常有用的类,它非常容易执行子类化并触发 MouseMove 事件。

看看这个here,看看子类化是如何工作的......好吧,它是用VB.NET编写的,但是如果你愿意的话,把它翻译成C#真的很容易,我想象的代码看起来像这样: 注意:我包含的这段代码是我的头等大事,所以这可能有一个错误......但这就是它的要点。

编辑:作为对 Joe White 评论的回应,我已经包含了修改后的代码,它确实发送了 WM_MOUSEMOVE ......看看下面的步骤,了解我如何在 VS 2008 Pro 下复制它。

    公共类 MyGroupBox : System.Windows.Forms.GroupBox
    {
        私有子类 sc;
        私有常量 int WM_MOUSEMOVE = 0x200;
        公共委托无效 MyMouseMoveEventHandler(对象发送者,System.EventArgs e);
        公共事件 MyMouseMoveEventHandler MyMouseMove;
        公共 MyGroupBox()
            : 根据()
        {
            sc = new SubClass(this.Handle, true);
            sc.SubClassedWndProc += new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
        }

        受保护的覆盖无效处置(布尔处置)
        {
            如果(sc.SubClassed)
            {
                sc.SubClassedWndProc -= 新的 SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
                sc.SubClassed = 假;
            }
            base.Dispose(处置);
        }
        私人无效 OnMyMouseMove()
        {
            if (this.MyMouseMove != null) this.MyMouseMove(this, System.EventArgs.Empty);
        }
        void sc_SubClassedWndProc(参考消息 m)
        {
            if (m.Msg == WM_MOUSEMOVE) this.OnMyMouseMove();
        }

    }

    #region SubClass 类处理程序类
    公共类子类:System.Windows.Forms.NativeWindow
    {
        公共代表无效
          SubClassWndProcEventHandler(参考 System.Windows.Forms.Message m);
        公共事件 SubClassWndProcEventHandler SubClassedWndProc;
        私有布尔 IsSubClassed = false;

        公共子类(IntPtr 句柄,布尔 _SubClass)
        {
            base.AssignHandle(句柄);
            this.IsSubClassed = _SubClass;
        }

        公共布尔子类
        {
            得到 { 返回 this.IsSubClassed; }
            设置 { this.IsSubClassed = value; }
        }

        受保护的覆盖无效 WndProc(参考消息 m)
        {
            如果(this.IsSubClassed)
            {
                OnSubClassedWndProc(参考 m);
            }
            base.WndProc(参考 m);
        }

        #region HiWord 消息破解器
        public int HiWord(int Number)
        {
            返回 ((数字 >> 16) & 0xffff);
        }
        #endregion

        #region LoWord 消息破解器
        公共 int LoWord(int Number)
        {
            返回(数字和 0xffff);
        }
        #endregion

        #region MakeLong 消息破解器
        公共 int MakeLong(int LoWord, int HiWord)
        {
            返回 (HiWord << 16) | (低字 & 0xffff);
        }
        #endregion

        #region MakeLParam 消息破解器
        公共 IntPtr MakeLParam(int LoWord,int HiWord)
        {
            返回 (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
        }
        #endregion

        私人无效 OnSubClassedWndProc(参考消息 m)
        {
            if (SubClassedWndProc != null)
            {
                this.SubClassedWndProc(ref m);
            }
        }
    }
    #endregion

  1. 创建一个简单的空白表格。
  2. 从工具面板中拖动一个组框并将其放入表单中,默认名称为groupBox1
  3. 在表单的设计器代码中,通过执行以下操作更改代码引用:
    System.Windows.Forms.GroupBox groupBox1;
    WindowsApplication.MyGroupBox groupBox1;
  4. 在该InitializeComponent()方法中,将 GroupBox 的实例化更改为:
    this.groupBox1 = new WindowsApplication.MyGroupBox();
  5. 保存并编译它。
  6. 返回到您的设计器窗口并单击组框,MyMouseMove在属性工具箱中查找事件,然后将其连接起来。
  7. 您的事件处理程序应如下所示:
        私人无效组框1_MyMouseMove(对象发送者,EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("MyMouseMove!");
        }

运行应用程序,每次在组框内移动鼠标时,您都会看到输出“MyMouseMove!”。

希望这能给你提示,最好的问候,汤姆。

于 2010-01-01T18:06:40.560 回答