2009-11-10 3 views
3

WinForms GroupBox 컨트롤은 MouseMove를 지원하지 않습니다 (또는 적어도 일관되게는 지원되지 않음). 이유를 알 수 없습니다.GroupBox에 MouseMove 이벤트가없는 이유는 무엇입니까?

Control에서 파생되었으므로 MouseMove 이벤트가 발생하지만 GroupBox는 명시 적으로 Browsable(false)으로 다시 입력하므로 속성 표에 표시되지 않습니다. FlatStyle이 Standard에 남아있는 한 Runtime에 MouseMove 이벤트를 연결하고 때로는 작동합니다. GroupBox의 FlatStyle이 System으로 설정된 경우 MouseMove 이벤트가 전혀 발생하지 않습니다.

반사경이 내게 단서를 제공하지 않았습니다. GroupBox 생성자는 이상한 컨트롤 스타일을 설정하지 않는 것 같으며 GroupBox는 MouseMove를 재정의하는 것과 같이 바보 같은 작업을 수행하지 않으며 기본 호출을하지 못합니다.

Delphi 그룹 상자가 OnMouseMove를 제대로 지원하므로 WinForms 관련 제한 사항 인 것처럼 보입니다.수정 : 델파이와의 비교가 유효하지 않습니다. Delphi 그룹 상자는 실제로 표준 BM_GROUPBOX 컨트롤이 아닙니다. 그들은 단지 에 그림을 그려 넣었습니다. 그룹 상자처럼처럼 보입니다. 실제로 이상한 그룹 박스 동작을 상속받지 않았습니다. 이것은 Windows 그룹 박스 컨트롤의 제한 일 수 있습니다. 그러나 어디에서나 문서화 된 것을 보지 못했습니다.

왜 WinForms GroupBox는 MouseMove를 지원하지 않습니까?

답변

4

this thread에 따르면 표준 Windows 그룹 상자 (즉, BS_GROUPBOX 스타일의 BUTTON 컨트롤)는 WM_NCHITTEST에 대한 응답으로 HTTRANSPARENT를 반환합니다. 컨트롤이 투명하다고 주장하기 때문에 Windows는 마우스 이동 이벤트를 대신 부모 창에 보냅니다.

스레드는 WM_NCHITTEST를 직접 처리하고 HTCLIENT를 반환하면 그룹 상자에 마우스 이동 이벤트가 발생 함을 확인합니다. 그들은 MFC를 사용하고 있지만 아마도 WinForms에서도 작동 할 것입니다.

명확하지 않은 점은 입니다. 이유는 Windows가 HTTRANSPARENT를 반환하지만 적어도 문제는 독립적으로 확인되었습니다.

2

Reflector에서 볼 수있는 키 속성은 CreateParams와 내부 OwnerDraw 속성입니다. GroupBox는 일반적으로 FlatStyle = System을 설정할 때를 제외하고 OwnerDraw = true로 작동합니다. 그런 다음 구식 Windows 그룹 상자, 클래스 이름이 BUTTON이고 BS_GROUPBOX 스타일 비트가 켜진 창을 얻습니다.

Spy ++를 살펴보면 컨트롤에 마우스 메시지가 전혀 표시되지 않습니다. 이유는 모르겠지만 SDK 개발자는이를 언급하지 않습니다. 나는이 모든 것이 반복되는 Windows 2.x로 거슬러 올라간다. 그러나 MouseMove 이벤트가 숨겨진 이유를 설명합니다. 시스템 스타일이 선택되면이를 실행할 수 없습니다. 클릭 및 위/아래와 동일합니다. FlatStyle 속성 setter는 Control.UserMouse 컨트롤 스타일을 해제하여 실제 스타일을 손톱에 고정시킵니다.

아무튼, 마우스 메시지를 원한다면 시스템 스타일을 피해야합니다.

0

그룹 상자는 다른 컨트롤이 들어있는 정적 컨트롤입니다. 올바르게 배치 된 경우 사용자 인터페이스를 직관적으로 만들기 위해 모든 것을 "그룹화"하기 위해 설계되었습니다. 따라서 GroupBox를 대신하여 사용할 수있는 이벤트가 거의 없습니다.

GroupBox에서 상속 된 클래스를 하위 클래스로 만들고 마우스 이동 이벤트를 가로 채기 위해 새 클래스를 만들 수 있습니다.이전에 사용한 적이있는 매우 유용한 클래스가 있으며 하위 클래 싱을 수행하고 MouseMove에 대한 이벤트를 트리거하는 것은 정말 쉽습니다.

서브 클래스가 어떻게 작동하는지 알기 위해이 here을 보아라. 좋아, VB.NET으로 작성되었지만, C#으로 변환하는 것은 정말 쉽다. 내가 상상하는 코드이다. 참고 : 여기에 포함 된 코드는 내 머리 위로 가기 때문에 오류가있을 수 있지만 그 것이 핵심입니다.

편집 : 조 화이트의 의견에 대응, 나는 수정 된 코드를 포함하고는 ... WM_MOUSEMOVE를 보내 내가 VS 2008 프로에서이 문제를 재현하는 방법에 대한 아래의 단계를 살펴 않습니다.

 
    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;
  4. WindowsApplication.MyGroupBox groupBox1;
    InitializeComponent() 내 메서드를 사용하여 GroupBox의 인스턴스를 다음으로 변경하십시오.
    this.groupBox1 = new WindowsApplication.MyGroupBox();
  5. 저장하고 컴파일 만하면됩니다.
  6. 디자이너 창으로 돌아가서 그룹 상자를 클릭하고 속성 도구 상자 내에서 MyMouseMove 이벤트를 찾아 연결합니다.
  7. 이벤트 핸들러는 다음과 같이 보일 것이다 :
 
     private void groupBox1_MyMouseMove(object sender, EventArgs e) 
     { 
      System.Diagnostics.Debug.WriteLine("MyMouseMove!"); 
     } 

는 응용 프로그램을 실행하고 매번 당신이 출력 표시되는 그룹 상자 내부의 마우스 이동 'MyMouseMove를!'.

희망 사항은 힌트를 제공합니다. 감사합니다. 탐.

+0

다른 응답이'WM_MOUSEMOVE'이 있는지 확인하기 때문에 나는 회의적 :

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

이것은 다음과 같은 방법을 트리거합니다 그룹 박스에 보내지도 않습니다. 이 코드가 실제로 GroupBox와 작동하는지 테스트 해 보셨습니까? –

+0

@Joe White : 제 수정 된 코드와이 코드가 작동하도록하는 단계를 참조하십시오. HTH. 안부 인사, 톰. – t0mm13b

0

VS에서는 이벤트 탭 (속성 아래)을 통해 특정 컨트롤에 대한 많은 이벤트에 액세스 할 수없는 것으로 나타났습니다. 당신은 InitializeComponents()에서 부모 폼의 디자이너에서 직접 이벤트 핸들러를 할당 할 수

private void groupBox1_MouseMove(object sender, MouseEventArgs e) 
{ 
    //doodle the stuff you want to happen after the trigger here 
}; 
+0

"런타임시 MouseMove 이벤트를 후킹 할 수 있으며 때로는 FlatStyle이 Standard에 남아있는 한 작동합니다 .GolBox의 FlatStyle이 System으로 설정된 경우 MouseMove 이벤트가 실행되지 않습니다. 모든." –