2009-05-01 19 views
6

私はC#でカスタムコントロールを実装しようとしています。マウスを動かしたときにイベントを取得する必要があります。私はMouseHoverイベントがあることを知っていますが、それは一度だけ発生します。もう一度発射するには、コントロールのマウスを持ってもう一度それを入力する必要があります。コントロール内の複数のMouseHoverイベント

私はこれを達成する方法はありますか?

+0

あなたは明確にできますか? x/y座標があなたのコントロール上にホバリングしているときに変化するたびにイベントが欲しいですか? –

+0

マウスが動かなくなるたびにイベントを取得したい。私もMouseMoveイベントをフックしますが、マウスの動きが止まるときを知る必要があります。 MouseHoverイベントを使用する以外の方法がありますか? –

答えて

8

"移動停止"は、 "nミリ秒の間にピクセルの半径がxの範囲内にとどまる"としましょう。

MouseMoveイベントを登録し、タイマー(nに設定)を使用してタイムアウトを設定します。マウスが動くたびに、公差に対してチェックします。許容範囲外の場合は、タイマーをリセットして新しい原点を記録します。

擬似コード:

Point lastPoint; 
const float tolerance = 5.0; 

//you might want to replace this with event subscribe/unsubscribe instead 
bool listening = false; 

void OnMouseOver() 
{ 
    lastpoint = Mouse.Location; 
    timer.Start(); 
    listening = true; //listen to MouseMove events 
} 

void OnMouseLeave() 
{ 
    timer.Stop(); 
    listening = false; //stop listening 
} 

void OnMouseMove() 
{ 
    if(listening) 
    { 
     if(Math.abs(Mouse.Location - lastPoint) > tolerance) 
     { 
      //mouse moved beyond tolerance - reset timer 
      timer.Reset(); 
      lastPoint = Mouse.Location; 
     } 
    } 
} 

void timer_Tick(object sender, EventArgs e) 
{ 
    //mouse "stopped moving" 
} 
+0

ありがとう、私はそれを試してみます。 :) –

+0

私はタイマーを使ってずっと簡単に何かをやってしまった。それは「ハックシ」のようなものだが、仕事を終わらせる。助けてくれてありがとう。 –

+0

@lc:私は似たような実装をしていますが、 "公差"を使う必要はないと分かりました。最後のマウスの位置が現在の位置と異なるかどうかを確認するだけで問題ありません。 –

2

なぜ、MouseLeaveイベントでの退会、MouseHoverイベントでのMouseMoveイベントをサブスクライブしませ

編集:停止したマウスは、タイマーを毎回起動するかどうかを判別でき

一つの方法は、あなたマウスの移動イベントを取得すると、タイマーが経過したときにマウスが停止したとみなすことができます。 MouseLeaveでMouseMoveイベントを削除する理由は、マウスがコントロールの上にあるときだけイベントを受け取るためです。

+0

あなたは何を意味するのかを明確にすることはできますか?私は既にMouseMoveイベントを処理しており、マウスが動いているときだけ通知し、停止していないときは通知しません。 –

+0

Heh。同じ考え。 +1 –

+0

私はタイマーの使用について考えていました。私は明日それを試してみるつもりです。マウスがコントロールの外にあってもマウスイベントを受け取る必要があるので、私は他のオプションを使用できません。 –

5

私は、これは古い話題であることを認識しますが、私はそれを行うことが見いださ方法を共有したいと思った:マウス移動イベントコールResetMouseEventArgsに()イベントをキャッチコントロール上に。

+2

これは私にとってはうまくいかなかった。 – snarf

1

これは私が思い付く最もクリーンな実装でした。それはかなりうまく動作します:

[DllImport("user32.dll")] 
    static extern IntPtr SendMessage 
    (
     IntPtr controlHandle, 
     uint message, 
     IntPtr param1, 
     IntPtr param2 
    ); 

    const uint WM_MOUSELEAVE = 0x02A3; 

    Point lastMousePoint = Point.Empty; 

    void richTextBox_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (Math.Abs(e.Location.X - lastMousePoint.X) > 1 || Math.Abs(e.Location.Y - lastMousePoint.Y) > 1) 
     { 
      lastMousePoint = e.Location; 

      SendMessage((sender as RichTextBox).Handle, WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero); 
     } 
    } 

    void richTextBox_MouseHover(object sender, EventArgs e) 
    { 
     foo(); 
    } 
0

ここでは、タイマーに依存しない、少しシンプルなバージョンです。最後にマウスを移動した時刻を記録し、マウスがホバリングしているかどうかを確認するときはいつでも現在の時刻を比較するだけです。

private DateTime mouseMoveTime = DateTime.Now; 
    private Point mouseMoveLoc = new Point(); 

    private bool IsHovering() 
    { 
     return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0; 
    } 

    private void myControl_MouseMove(object sender, MouseEventArgs e) 
    { 
     // update mouse position and time of last move 
     if (Math.Abs(e.X - mouseMoveLoc.X) > SystemInformation.MouseHoverSize.Width || 
      Math.Abs(e.Y - mouseMoveLoc.Y) > SystemInformation.MouseHoverSize.Height) 
     { 
      mouseMoveLoc = new Point(e.X, e.Y); 
      mouseMoveTime = DateTime.Now; 
     } 
    } 

距離の許容差がない非常に短いバージョンです。

private DateTime mouseMoveTime = DateTime.Now; 

    private bool IsHovering() 
    { 
     return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0; 
    } 

    private void myControl_MouseMove(object sender, MouseEventArgs e) 
    { 
     mouseMoveTime = DateTime.Now; 
    } 

マウスが動いているかどうかを確認する必要がある場合は、if(IsHovering())...を使用してください。

ドラッグしたときにMouseMoveが起動されないことに気づいたことがあります。ただし、ドラッグしたイベントにmouseMoveTime/Locの更新コードをコピーして、これを取得することができます。

関連する問題