2009-05-01 12 views
6

Estoy tratando de implementar un control personalizado en C# y necesito obtener eventos cuando el mouse está suspendido. Sé que existe el evento MouseHover, pero solo se dispara una vez. Para que vuelva a disparar, necesito tomar el mouse del control e ingresarlo nuevamente.Varios eventos MouseHover en un control

¿Hay alguna manera de que pueda lograr esto?

+0

¿Puedes aclarar? ¿Desea un evento cada vez que las coordenadas x/y cambian cuando está sobre su control? –

+0

Deseo obtener un evento cada vez que el mouse deje de moverse. También engancho el evento MouseMove, pero necesito saber cuándo deja de moverse el mouse. ¿Hay alguna otra forma de hacer esto que usar el evento MouseHover? –

Respuesta

8

Definamos "deja de moverse" porque "permanece dentro de un radio de x píxeles para n ms".

Suscríbase al evento MouseMove y use un temporizador (establecido en n ms) para establecer el tiempo de espera. Cada vez que el mouse se mueve, verifica la tolerancia. Si está fuera de su tolerancia, restablezca el temporizador y registre un nuevo origen.

Pseudocódigo:

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

Gracias, intentaré eso. :) –

+0

Terminé haciendo algo mucho más simple usando un temporizador. Es un poco "hackish" pero hace el trabajo bien. Gracias por la ayuda. –

+0

@lc: Tengo una implementación similar, pero no he encontrado necesario usar una "tolerancia". Solo verifica si la ubicación del último mouse es diferente de la actual funciona bien. –

2

Por qué no suscribirse a los eventos MouseMove en caso MouseHover, a continuación, darse de baja en caso MouseLeave

Editar:

Una forma de determinar si el ratón se detuvo sería iniciar un temporizador cada vez que se obtener un evento de movimiento del mouse, cuando el temporizador haya transcurrido, entonces podría considerar que el mouse se detuvo. La razón para eliminar los eventos de MouseMove en MouseLeave le permitiría recibir solo eventos mientras el mouse está sobre su control.

+0

¿Puedes aclarar a qué te refieres? Ya manejo el evento MouseMove y solo me dice cuándo se mueve el mouse, no cuando se detiene. –

+0

Heh. La misma idea. +1 –

+0

Pensé en usar un temporizador. Voy a intentar eso mañana. Y no puedo usar la otra opción porque necesito recibir eventos del mouse incluso cuando el mouse está fuera del control. –

5

Soy consciente de que este es un viejo tema, pero quería compartir una manera que encontré para hacerlo: en los ResetMouseEventArgs llamadas movimiento del ratón evento() en el control que atrapa el evento .

+2

Esto no funcionó para mí. – snarf

1

Esta fue la implementación más limpia que pude encontrar. Funciona bastante bien:

[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

Aquí hay una versión un poco más simple que no depende de un temporizador. Simplemente registre la hora del último movimiento del mouse y luego compare la hora actual cada vez que quiera verificar si el mouse está moviendo el mouse.

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; 
     } 
    } 

O una versión realmente corta que no tiene una tolerancia de distancia.

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; 
    } 

sólo tiene que utilizar si (IsHovering()) ... cuando es necesario comprobar si el ratón se está moviendo.

Una cosa que he notado es que MouseMove no se dispara cuando estás arrastrando. Sin embargo, puede copiar el código de actualización mouseMoveTime/Loc a su evento de arrastre para evitar esto.

Cuestiones relacionadas