2009-03-16 7 views
0

フォームのOnMouseEnterイベントハンドラとOnMouseLeaveイベントハンドラがあります。マウスがフォームの上を移動すると、不透明度を100%に設定したい場合は、不透明度を25%に設定します。マウスがフォーム上のボタンの上を移動する場合を除いて、正常に機能します。 OnMouseLeaveイベントは、フォームを再度発生させて非表示にします。フォーム上のすべてのコントロールに対してOnMouseEnterを呼び出す必要なく、これを処理する良い方法はありますか?フォーム上のすべてのコントロールのOnMouseEnter

答えて

2

編集:確実に動作させることはできませんが、この回答はここに残します。理由:誰かが同じことをやるのを防ぐためです。それが動作しない理由については、メッセージの終わりを参照してください。

あなたはカーソルの位置を取得し、それがフォームのクライアント領域内だかどうかを確認するためにチェックすることによって、クライアント領域の四角形のためにかなり簡単にこれを行うことができます

:これはあなたの子コントロールのいずれも変更されないことを前提としてい

private void Form1_MouseLeave(object sender, EventArgs e) 
{ 
    Point clientPos = PointToClient(Cursor.Position); 
    if (!ClientRectangle.Contains(clientPos)) 
    { 
     this.Opacity = 0.25; 
    } 
} 

不透明度。

ただし、マウスがタイトルバーに移動すると、フォームは0.25%になるため、完璧なソリューションではありません。マウスの位置がウィンドウの矩形内にあるかどうか(Boundsプロパティを使用して)確認することで修正できますが、マウスがタイトルバーの外に出てウィンドウの外に出ると、ウィンドウは不透明のままです。

外部からタイトルバーを入力する際に​​も同様の問題があります。

この作業を確実に行うには、WM_NCMOUSEENTERWM_NCMOUSELEAVEのメッセージを処理する必要があります。

なぜ機能しないのですか: クライアント以外の領域通知を処理することもできません。マウスが子コントロールに入力する可能性があり、フォームが通知されないようにします。

2

すべての子のMouseEnterイベントとMouseLeaveイベントを処理することはできませんが、手動でワイヤリングする必要はありません。

私のプロジェクトから貼り付けた&をコピーしたコードです。あなたがここで説明したことはほとんどありません。私は実際にアイデアとフレームワークをthis siteからコピーしました。

コンストラクタでは、AttachMouseOnChildren()を呼び出してイベントをアタッチします。

OnContainerEnterとOnContainerLeaveは、フォーム自体に出入りするマウスを処理するために使用されます。

#region MouseEnter & Leave 

    private bool _childControlsAttached = false; 

    /// <summary> 
    /// Attach enter & leave events to child controls (recursive), this is needed for the ContainerEnter & 
    /// ContainerLeave methods. 
    /// </summary> 
    private void AttachMouseOnChildren() { 
     if (_childControlsAttached) { 
      return; 
     } 
     this.AttachMouseOnChildren(this.Controls); 
     _childControlsAttached = true; 
    } 

    /// <summary> 
    /// Attach the enter & leave events on a specific controls collection. The attachment 
    /// is recursive. 
    /// </summary> 
    /// <param name="controls">The collection of child controls</param> 
    private void AttachMouseOnChildren(System.Collections.IEnumerable controls) { 
     foreach (Control item in controls) { 
      item.MouseLeave += new EventHandler(item_MouseLeave); 
      item.MouseEnter += new EventHandler(item_MouseEnter); 
      this.AttachMouseOnChildren(item.Controls); 
     } 
    } 

    /// <summary> 
    /// Will be called by a MouseEnter event, with any of the controls within this 
    /// </summary> 
    void item_MouseEnter(object sender, EventArgs e) { 
     this.OnMouseEnter(e); 
    } 

    /// <summary> 
    /// Will be called by a MouseLeave event, with any of the controls within this 
    /// </summary> 
    void item_MouseLeave(object sender, EventArgs e) { 
     this.OnMouseLeave(e); 
    } 

    /// <summary> 
    /// Flag if the mouse is "entered" in this control, or any of its children 
    /// </summary> 
    private bool _containsMouse = false; 

    /// <summary> 
    /// Is called when the mouse entered the Form, or any of its children without entering 
    /// the form itself first. 
    /// </summary> 
    protected void OnContainerEnter(EventArgs e) { 
     // No longer transparent 
     this.Opacity = 1; 
    } 

    /// <summary> 
    /// Is called when the mouse leaves the form. When the mouse leaves the form via one of 
    /// its children, this will also call OnContainerLeave 
    /// </summary> 
    /// <param name="e"></param> 
    protected void OnContainerLeave(EventArgs e) { 
     this.Opacity = DEFAULT_OPACITY; 
    } 

    /// <summary> 
    /// <para>Is called when a MouseLeave occurs on this form, or any of its children</para> 
    /// <para>Calculates if OnContainerLeave should be called</para> 
    /// </summary> 
    protected override void OnMouseLeave(EventArgs e) { 
     Point clientMouse = PointToClient(Control.MousePosition); 
     if (!ClientRectangle.Contains(clientMouse)) { 
      this._containsMouse = false; 
      OnContainerLeave(e); 
     } 
    } 
    /// <summary> 
    /// <para>Is called when a MouseEnter occurs on this form, or any of its children</para> 
    /// <para>Calculates if OnContainerEnter should be called</para> 
    /// </summary> 
    protected override void OnMouseEnter(EventArgs e) { 
     if (!this._containsMouse) { 
      _containsMouse = true; 
      OnContainerEnter(e); 
     } 
    } 

    #endregion 
+0

唯一の問題は、それがDEFAULT_OPACITYに不透明度を設定していることですマウスがタイトルバーの上にあるとき。 – Samuel

0

あなたが興味を持っているマウスイベントを確実に処理する方法の1つは、Applicationオブジェクトにを設定して、子コントロールに送信されたとしてもすべてのマウスメッセージ(WM_MOUSEMOVEなど)フォームの。

ここではいくつかのデモコードです:

using System; 
using System.Windows.Forms; 

namespace Test 
{ 
    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     public static Form frm = null; 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      frm = new Form1 {Opacity = 0.25}; 
      frm.Controls.Add(new Button{Dock = DockStyle.Fill, Text = "Ok"}); 

      Application.AddMessageFilter(new MouseMoveFilter()); 
      Application.Run(frm); 
     } 
    } 

    public class MouseMoveFilter : IMessageFilter 
    { 
     #region IMessageFilter Members 
     private const int WM_MOUSELEAVE  = 0x02A3; 
     private const int WM_NCMOUSEMOVE = 0x0A0; 
     private const int WM_MOUSEMOVE  = 0x0200; 
     private const int WM_NCMOUSELEAVE = 0x2A2; 

     public bool PreFilterMessage(ref Message m) 
     { 
      switch (m.Msg) 
      { 
       case WM_NCMOUSEMOVE: 
       case WM_MOUSEMOVE: 
        Program.frm.Opacity = 1; 
        break; 

       case WM_NCMOUSELEAVE: 
       case WM_MOUSELEAVE: 
        if (!Program.frm.Bounds.Contains(Control.MousePosition)) 
         Program.frm.Opacity = 0.25; 
        break; 

      } 
      return false; 
     } 

     #endregion 
    } 
} 

また、フォームクラスから継承し、PreProcessMessageを(上書きすることができます)同じことを達成するために...

関連する問題