トップ回答者
フォームにおけるmouseleaveイベント

質問
-
windows 7 64bitで visual studio 11を使っています。
開発言語visual C#でWindowsアプリケーションを作っています。
まだまだ勉強中ですがよろしくお願いいたします。
フォームからマウスが外れたら閉じる設定にしたいと思っています。
そのフォームにおいてmouselieveイベントで this.Close(); this.Dispose();を記述しても反応しません。
そのフォーム内にはlistviewコントロールがひとつあるのですが、そのlistviewコントロールにおいて
mouseleveイベントにthis.Close(); this.Dispose();を記述すると狙い通りフォームが閉じます。
しかし、その場合listviewコントロールのスクロールバーに触れてもmouseleaveイベントが発生してしまうので
どうしたらいいのかわからなくなりました。
解決策よろしくお願いいたします。
回答
-
MouseMoveで別のフォームがあるときは無効化して、ないときは領域外に出たら閉じるという命令をつくればいいのでしょうか?
それで良いと思います。
MouseMoveやMouseLeaveはクライアント領域内でのみ有効ですので、ウインドウ領域から外れた時に判断したいのでしたら、以下のようにWM_NCMOUSELEAVE を使えば良いでしょう。private const int WM_NCMOUSELEAVE = 0x02A2; protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case WM_NCMOUSELEAVE: if (!this.Bounds.Contains(Cursor.Position)) this.Close(); break; } }
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク millionx 2012年1月23日 11:53
-
一つ問題がありまして、マウスの動きが速いと反応してくれませんねぇ。
確かにそうですね。これを回避するのは難しそうです。
この代替案としては、millionxさんが上でご紹介されていたatmarkitの記事を参考にして、タイマーを使って一定間隔で監視した方が良さそうです。
フォームのMouseEnterイベントでタイマーをスタートさせ、100ms間隔で監視させます。これだとマウスポイントを高速に動かしても原理上、問題なく動作します。private void Form1_MouseEnter(object sender, EventArgs e) { this.timer1.Start(); } private void timer1_Tick(object sender, EventArgs e) { if (!this.Bounds.Contains(Cursor.Position)) this.Close(); }
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク millionx 2012年1月26日 12:37
すべての返信
-
手元のVS2008でやってみましたが、イベント自体は動いているように思います。
public Form1() { this.MouseLeave += new EventHandler(Form1_MouseLeave); // これがあるか確認 } void Form1_MouseLeave(object sender, EventArgs e) { this.Close(); }
"// これがあるか確認" のイベントの登録がコンストラクタかForm1.Designer.csにちゃんとあるか確認してください。
で、それはできたとして、たとえばフォームにDataGridViewなどがある場合、その上にマウスが行くと閉じてしまいますが、
それは意図した動作ではないですよね?なのでMouseLeaveではだめなのではと思います。 -
素早い回答ありがとうございます。
Designer.csのほうに登録されていましたのでそこはクリアされました。
フォーム外にマウスが出ると閉じるフォームにはlistviewコントロールだけです。
で、投稿した後もう一つ問題が発覚しました。そのlistviewコントロールでさらに別のフォームを出したいのですが、
それを出すとMouseLeaveイベントが発生してしまうので、おっしゃるとおりMouseLeaveではだめなようです。
MouseMoveで別のフォームがあるときは無効化して、ないときは領域外に出たら閉じるという命令をつくればいいのでしょうか?
まだ試していませんが、下記リンクで実現できそうな気がしますので試してみたいと思います、
http://www.atmarkit.co.jp/fdotnet/dotnettips/382ctrlcontain/ctrlcontain.html
-
例えばですが、MouseLeaveイベントの中で下記の動作をしてはいかがですか?
bool doClose = false; if (Cursor.Position.X < 0) { doClose = true; } if (Cursor.Position.Y < 0) { doClose = true; } if (Cursor.Position.X > this.Width) { doClose = true; } if (Cursor.Position.Y > this.Height) { doClose = true; } if (doClose) { this.Close(); }
-
MouseMoveで別のフォームがあるときは無効化して、ないときは領域外に出たら閉じるという命令をつくればいいのでしょうか?
それで良いと思います。
MouseMoveやMouseLeaveはクライアント領域内でのみ有効ですので、ウインドウ領域から外れた時に判断したいのでしたら、以下のようにWM_NCMOUSELEAVE を使えば良いでしょう。private const int WM_NCMOUSELEAVE = 0x02A2; protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case WM_NCMOUSELEAVE: if (!this.Bounds.Contains(Cursor.Position)) this.Close(); break; } }
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク millionx 2012年1月23日 11:53
-
回答ありがとうございます。
私の環境ではなぜかフォームのMouseLeaveイベントが起きないみたいです。
しかし、ご提示いただいたコードは別のとこで大変参考になりました。
実際動くならば以下のようにしたほうがいいでしょうね。
bool doClose = false; if (Cursor.Position.X < this.Location.X) { doClose = true; } if (Cursor.Position.Y < this.Location.Y) { doClose = true; } if (Cursor.Position.X > this.Width) { doClose = true; } if (Cursor.Position.Y > this.Height) { doClose = true; } if (doClose) { this.Close(); }
-
Position と Location の件、すいません未検証でした。
確認しましたが、どちらにせよダメっぽいですね。
Form_MouseLeaveだと、Formの内側(Border部の内側)から出る時にイベントが発生してしまい、
恐らく求めるタイミングと違ってしまいそうです。
※FormBorderStyle = None のケースであれば求める動作をしそうですが、意味無いですよね。
WndProc でOKとの事なので構わないのですが、気になったので・・・
>>MouseLeaveイベントが起きないみたいです。
ハンドラが消されてしまっているとか、何かの間違いじゃないですかね。
-
一つ問題がありまして、マウスの動きが速いと反応してくれませんねぇ。
確かにそうですね。これを回避するのは難しそうです。
この代替案としては、millionxさんが上でご紹介されていたatmarkitの記事を参考にして、タイマーを使って一定間隔で監視した方が良さそうです。
フォームのMouseEnterイベントでタイマーをスタートさせ、100ms間隔で監視させます。これだとマウスポイントを高速に動かしても原理上、問題なく動作します。private void Form1_MouseEnter(object sender, EventArgs e) { this.timer1.Start(); } private void timer1_Tick(object sender, EventArgs e) { if (!this.Bounds.Contains(Cursor.Position)) this.Close(); }
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク millionx 2012年1月26日 12:37