2009-05-01 3 views
6

Sto cercando di implementare un controllo personalizzato in C# e ho bisogno di ottenere eventi quando il mouse è al passaggio del mouse. So che c'è l'evento MouseHover ma si attiva solo una volta. Per farlo sparare di nuovo ho bisogno di prendere il mouse del controllo e inserirlo di nuovo.Mouse multipli Eventi in un controllo

C'è qualche modo per farlo?

+0

Potete chiarire? Vuoi un evento ogni volta che le coordinate x/y cambiano quando passa il mouse sopra il tuo controllo? –

+0

Voglio ottenere un evento ogni volta che il mouse si ferma. Ho anche agganciato l'evento MouseMove, ma ho bisogno di sapere quando il mouse si ferma. C'è un altro modo per farlo rispetto all'utilizzo dell'evento MouseHover? –

risposta

8

Definiamo "arresti in movimento" come "rimane entro un raggio di x pixel per n ms".

Iscriviti all'evento MouseMove e utilizza un timer (impostato su n ms) per impostare il timeout. Ogni volta che il mouse si muove, controllare la tolleranza. Se è fuori tolleranza, resettare il timer e registrare una nuova origine.

Pseudocodice:

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

Grazie, ci proverò. :) –

+0

Ho finito per fare qualcosa di molto più semplice usando un timer. È una specie di "hackish" ma fa il lavoro. Grazie per l'aiuto. –

+0

@lc: Ho un'implementazione simile, ma non ho trovato necessario utilizzare una "tolleranza". Solo controllando se l'ultima posizione del mouse è diversa da quella corrente funziona correttamente. –

2

Perché non iscriversi agli eventi MouseMove in caso MouseHover, quindi annullare l'iscrizione in caso MouseLeave

Edit:

Un modo per determinare se il mouse viene fermato potrebbe essere quella di avviare un timer ogni volta che si ottenere un evento di spostamento del mouse, quando il timer è trascorso, si potrebbe prendere in considerazione l'interruzione del mouse. Il motivo della rimozione degli eventi MouseMove su MouseLeave consente di ricevere solo eventi mentre il mouse ha il controllo del mouse.

+0

Puoi chiarire cosa intendi? Gestisco già l'evento MouseMove e mi dice solo quando il mouse si muove, non quando viene fermato. –

+0

Heh. Stessa idea +1 –

+0

Avevo pensato di usare un timer. Ci proverò domani. E non posso usare l'altra opzione perché devo ricevere gli eventi del mouse anche quando il mouse è fuori dal controllo. –

5

Mi rendo conto che questo è un argomento vecchio, ma ho voluto condividere un modo che ho trovato per farlo: sulle ResetMouseEventArgs chiamata evento del mouse Move() sul controllo che cattura l'evento .

+2

Questo non ha funzionato per me. – snarf

1

Questa è stata l'implementazione più pulita che potrei immaginare. Funziona abbastanza bene:

[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

Ecco una versione leggermente più semplice che non si basa su un timer. Basta registrare l'ora dell'ultima mossa del mouse per confrontare l'ora corrente ogni volta che si desidera controllare se il mouse è in bilico.

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 versione veramente breve che non ha una tolleranza di distanza.

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

Basta usare if (IsHovering()) ... quando è necessario controllare se il mouse è in movimento.

Una cosa che ho notato è che MouseMove non viene attivato durante il trascinamento. Puoi comunque copiare il codice di aggiornamento mouseMoveTime/Loc all'evento di trascinamento per aggirare questo problema.