WinForms GroupBox控件不支持MouseMove(或者至少不一致),我不明白为什么。
由于它来自Control,它确实有一个MouseMove事件,但是GroupBox明确地用Browsable(false)
重新引入它,所以它没有显示在Property Grid中。您可以在运行时挂钩MouseMove事件,有时它可以工作 - 只要FlatStyle保留在Standard。如果GroupBox的FlatStyle设置为System,则根本不会触发任何MouseMove事件。
Reflector没有给我任何线索。 GroupBox构造函数似乎没有设置任何奇怪的控件样式,GroupBox没有做任何愚蠢的事情,如覆盖MouseMove并且无法调用base。
这似乎也是WinForms特有的限制,因为Delphi组框支持OnMouseMove就好了。 更正:与Delphi的比较无效。 Delphi组框实际上并不是标准的BM_GROUPBOX控件;它们只是像组框一样被绘制成外观,而没有真正继承像这样的奇怪的groupbox行为。所以这可能是Windows组框控件的限制,但我没有在任何地方看到它。
为什么WinForms GroupBox不支持MouseMove?
答案 0 :(得分:4)
根据this thread,标准Windows组框(即具有BS_GROUPBOX样式的BUTTON控件)似乎返回HTTRANSPARENT以响应WM_NCHITTEST。由于控件声称是透明的,因此Windows将鼠标移动事件发送到其父窗口。
线程确认,如果你自己处理WM_NCHITTEST并返回HTCLIENT,那么groupbox将获得鼠标移动事件。他们使用的是MFC,但它也可能适用于WinForms。
为什么 Windows默认情况下会返回HTTRANSPARENT,但至少该问题已经过独立确认。
答案 1 :(得分:2)
您可以使用Reflector看到这一点,关键属性是CreateParams和内部OwnerDraw属性。 GroupBox通常以OwnerDraw = true运行,除非您设置FlatStyle = System。然后你得到一个老式的Windows组合框,一个类名为BUTTON且BS_GROUPBOX风格位打开的窗口。
如果你看看Spy ++,你会发现控件根本没有得到任何鼠标消息。不知道为什么会这样,SDK文档没有提到它。我猜这可以追溯到Windows 2.x,每个周期都计算在内。但它确实解释了为什么MouseMove事件被隐藏,它在选择系统样式时无法触发。 Click和Up / Down相同。 FlatStyle属性setter通过关闭Control.UserMouse控件样式来确定它。
Anyhoo,如果你想要鼠标消息,你需要避免系统风格。
答案 2 :(得分:0)
组框是一个静态控件,其中包含其他控件。它的设计纯粹是为了将事物“组合在一起”,以便在正确布局时使用户界面更直观。因此,您可以代表GroupBox使用很少的事件。
您可以创建一个继承自GroupBox的新类,并将其子类化以拦截鼠标移动事件。我之前使用过一个非常有用的类,很容易执行子类化并为MouseMove触发事件。
看一下这个here,看看子类化是如何工作的......好吧,它是用VB.NET编写的,但如果你愿意的话很容易将它翻译成C#,代码我想象看起来像这样: <击> 注意:我所包含的这段代码是我的头脑,因此可能会有错误......但这就是它的主旨。
编辑:为了回应Joe White的评论,我已经包含了修改后的代码,它确实发送了WM_MOUSEMOVE ...请看下面的步骤,了解我如何在VS 2008 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
groupBox1
System.Windows.Forms.GroupBox groupBox1;至
WindowsApplication.MyGroupBox groupBox1;
InitializeComponent()
方法中,将GroupBox的实例化更改为:this.groupBox1 = new WindowsApplication.MyGroupBox();
MyMouseMove
事件,然后将其连接起来。private void groupBox1_MyMouseMove(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine("MyMouseMove!"); }
运行应用程序,每次在组框内移动鼠标时,您都会看到输出'MyMouseMove!'。
希望这会给你提示, 最好的祝福, 汤姆。
答案 3 :(得分:0)
我注意到某些控件的很多事件无法通过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
};