GroupBox に MouseMove イベントがないのはなぜですか?
-
19-09-2019 - |
質問
WinForms GroupBox コントロールは MouseMove をサポートしていません (少なくとも、一貫してサポートしていません) が、その理由がわかりません。
これは Control から派生しているため、MouseMove イベントがありますが、GroupBox はこれを次のように明示的に再導入します。 Browsable(false)
, そのため、プロパティ グリッドには表示されません。実行時に MouseMove イベントをフックすることができ、FlatStyle が Standard のままである限り、機能する場合があります。GroupBox の FlatStyle が System に設定されている場合、MouseMove イベントはまったく発生しません。
リフレクターは何も手がかりを与えてくれませんでした。GroupBox コンストラクターは、奇妙なコントロール スタイルを設定していないようです。また、GroupBox は、MouseMove をオーバーライドしたり、base の呼び出しに失敗したりするような愚かなことはしません。
Delphi グループ ボックスは OnMouseMove を適切にサポートしているため、これは WinForms 固有の制限であるようです。 修正:Delphi との比較は無効です。Delphi グループ ボックスは、実際には標準の BM_GROUPBOX コントロールではありません。彼らはただ描かれているだけです 見て このような奇妙なグループボックスの動作を実際に継承することなく、グループ ボックスと同様に機能します。したがって、これは Windows グループボックス コントロールの制限である可能性がありますが、これについてはどこにも文書化されていません。
WinForms GroupBox が MouseMove をサポートしていないのはなぜですか?
解決
これによると、スレッドに、標準のWindowsグループボックス(BS_GROUPBOXスタイルで、すなわち、Buttonコントロールは)WM_NCHITTESTに応じてHTTRANSPARENTを返すように表示されます。コントロールが透明であることを主張しているので、Windowsが代わりにその親ウィンドウにマウスムーブイベントを送信します。
スレッドはあなたがWM_NCHITTEST自分で処理してHTCLIENTを返す場合は、ことを確認し、その後、グループボックスは、マウス移動イベントを取得します。彼らは、MFCを使用しているが、それはおそらく同様にWinFormsのために働くます。
どのようなはっきりしないのは、は、なぜのWindowsは、デフォルトでHTTRANSPARENTを返しているが、少なくとも問題が独立して確認されています。
他のヒント
あなたはリフレクターでこれを見ることができ、キープロパティは、CreateParamsを、内部OwnerDrawするプロパティです。 GroupBoxのは、通常、あなたがFlatStyle =システムを設定する場合を除き、真OwnerDrawする=で動作します。あなたは昔ながらのWindowsグループボックスを取得し、BS_GROUPBOXスタイルビットとそのクラス名のボタンでウィンドウがオンになっています。
あなたはスパイ++で見てみる場合は、は、コントロールがまったくマウスメッセージを取得していないことがわかります。なぜそうなのか、SDKのドキュメントはそれを言及していないわかりません。私は、これはバックすべてのサイクルがカウントされ、Windowsの2.xのにさかのぼり推測と思います。しかし、それは、MouseMoveイベントが隠されている理由は、システムのスタイルが選択されている場合、それが起動することはできません説明しません。クリックして、アップ/ダウンのために同じ。 FlatStyleプロパティのセッターもControl.UserMouseコントロールのスタイルをオフにすることで、実際に爪にそれをダウンます。
あなたがマウスメッセージをしたい場合は、Anyhoo、あなたはシステムのスタイルを避ける必要があります。
グループ ボックスは、内部に他のコントロールを収容する静的コントロールです。これは、単に物事を「グループ化」して、正しくレイアウトされていればユーザー インターフェイスを直観的にすることを目的として設計されています。したがって、GroupBox の代わりに使用できるイベントはほとんどありません。
GroupBox から継承する新しいクラスを作成し、それをサブクラス化してマウス移動イベントをインターセプトできる場合があります。以前に使用したことがある非常に便利なクラスがあり、サブクラス化を実行して MouseMove のイベントをトリガーするのは非常に簡単です。
これを見てください ここ サブクラス化がどのように機能するかを確認するには...OK、これは 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!」という出力が表示されます。
これがあなたにヒントを与えてくれることを願っています、よろしく、トム。
私は、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
};