代码之家  ›  专栏  ›  技术社区  ›  Joe White

为什么GroupBox没有mousemove事件?

  •  3
  • Joe White  · 技术社区  · 15 年前

    winforms groupbox控件不支持mousemove(或者至少不一致),我不明白为什么。

    因为它是从控件派生的,所以它确实有一个mousemove事件,但是groupbox显式地用重新引入它 Browsable(false) ,因此它不显示在属性网格中。您可以在运行时挂接mousemove事件,有时它也会工作——只要flatstyle是标准的。如果GroupBox的FlatStyle设置为System,则根本不会触发mousemove事件。

    反射镜没有给我任何线索。GroupBox构造函数似乎没有设置任何奇怪的控件样式,GroupBox也没有做任何愚蠢的事情,比如重写mousemove和调用base失败。

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

    为什么winforms groupbox不支持mousemove?

    4 回复  |  直到 7 年前
        1
  •  4
  •   Joe White    15 年前

    根据 this thread ,一个标准的Windows GroupBox(即具有b_GroupBox样式的按钮控件)似乎返回httransparent以响应wm_nchittest。因为控件声称是透明的,所以Windows会将鼠标移动事件发送到其父窗口。

    线程确认,如果您自己处理wm-nchittest并返回htclient,那么groupbox将获得鼠标移动事件。他们使用的是MFC,但它可能也适用于WinForms。

    不清楚的是 为什么? 默认情况下,Windows返回httransparent,但至少已独立确认问题。

        2
  •  2
  •   Hans Passant    15 年前

    您可以通过Reflector看到这个,key属性是createParams和内部ownerDraw属性。GroupBox通常在ownerDraw=true的情况下工作,除非设置了flatStyle=system。然后你会得到一个老式的Windows分组框,一个类名为button的窗口,其b_GroupBox样式位被打开。

    如果你用spy++,你会发现控件根本没有收到任何鼠标信息。不知道为什么会这样,sdk文档没有提到它。我想这可以追溯到Windows2.x,在那里每一个周期都计算在内。但它确实解释了为什么mousemove事件是隐藏的,当选择系统样式时它不能启动。单击和向上/向下相同。flatStyle属性设置器也通过关闭control.userMouse控件样式来将其固定下来。

    总之,如果你想要鼠标信息,你需要避免系统风格。

        3
  •  0
  •   t0mm13b    15 年前

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

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

    看看这个 here 要了解子类化是如何工作的……好吧,它是用vb.net编写的,但是很容易将其转换为c如果您愿意,我想象的代码如下所示: 注意:我所包含的代码在我的头上,所以可能有一个错误……但这是它的要点。

    编辑: 作为对JoeWhite的评论的回应,我已经包含了修改过的代码,它确实发送了wm_mousemove…请看下面的步骤,了解我如何在Vs2008 Pro下复制这个代码。

        public class MyGroupBox : System.Windows.Forms.GroupBox
        {
            private SubClass sc;
            private const int WM_MOUSEMOVE = 0x200;
            public delegate void MyMouseMoveEventHandler(object sender, System.EventArgs e);
            public event MyMouseMoveEventHandler MyMouseMove;
            public MyGroupBox()
                : base()
            {
                sc = new SubClass(this.Handle, true);
                sc.SubClassedWndProc += new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
            }
    
            protected override void Dispose(bool disposing)
            {
                if (sc.SubClassed)
                {
                    sc.SubClassedWndProc -= new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
                    sc.SubClassed = false;
                }
                base.Dispose(disposing);
            }
            private void OnMyMouseMove()
            {
                if (this.MyMouseMove != null) this.MyMouseMove(this, System.EventArgs.Empty);
            }
            void sc_SubClassedWndProc(ref Message m)
            {
                if (m.Msg == WM_MOUSEMOVE) this.OnMyMouseMove();
            }
    
        }
    
        #region SubClass Classing Handler Class
        public class SubClass : System.Windows.Forms.NativeWindow
        {
            public delegate void
              SubClassWndProcEventHandler(ref System.Windows.Forms.Message m);
            public event SubClassWndProcEventHandler SubClassedWndProc;
            private bool IsSubClassed = false;
    
            public SubClass(IntPtr Handle, bool _SubClass)
            {
                base.AssignHandle(Handle);
                this.IsSubClassed = _SubClass;
            }
    
            public bool SubClassed
            {
                get { return this.IsSubClassed; }
                set { this.IsSubClassed = value; }
            }
    
            protected override void WndProc(ref Message m)
            {
                if (this.IsSubClassed)
                {
                    OnSubClassedWndProc(ref m);
                }
                base.WndProc(ref m);
            }
    
            #region HiWord Message Cracker
            public int HiWord(int Number)
            {
                return ((Number >> 16) & 0xffff);
            }
            #endregion
    
            #region LoWord Message Cracker
            public int LoWord(int Number)
            {
                return (Number & 0xffff);
            }
            #endregion
    
            #region MakeLong Message Cracker
            public int MakeLong(int LoWord, int HiWord)
            {
                return (HiWord << 16) | (LoWord & 0xffff);
            }
            #endregion
    
            #region MakeLParam Message Cracker
            public IntPtr MakeLParam(int LoWord, int HiWord)
            {
                return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
            }
            #endregion
    
            private void OnSubClassedWndProc(ref Message 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. 事件处理程序应该如下所示:
            private void groupBox1_MyMouseMove(object sender, EventArgs e)
            {
                System.Diagnostics.Debug.WriteLine("MyMouseMove!");
            }
    

    运行应用程序,每次在GroupBox中移动鼠标时,都会看到输出“mymousemove!”.

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

        4
  •  0
  •   Peet    7 年前

    我注意到,许多特定控件的事件无法通过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
    };