2009-05-01 12 views
6

Próbuję zaimplementować niestandardowy formant w języku C# i muszę uzyskać zdarzenia, gdy mysz jest zawieszona. Wiem, że istnieje zdarzenie MouseHover, ale strzela tylko raz. Aby ponownie go uruchomić, muszę wziąć myszkę i wejść ponownie.Wiele zdarzeń MouseHover w kontrolce

Czy mogę to osiągnąć?

+0

Czy możesz wyjaśnić? Czy chcesz wydarzenie za każdym razem, gdy zmieniają się współrzędne x/y, gdy jest on zawieszony nad formantem? –

+0

Chcę uzyskać wydarzenie za każdym razem, gdy mysz przestaje się poruszać. Poddaję się również zdarzeniu MouseMove, ale muszę wiedzieć, kiedy mysz przestaje się poruszać. Czy jest inny sposób, aby to zrobić niż przy użyciu zdarzenia MouseHover? –

Odpowiedz

8

Zdefiniujmy "zatrzymuje ruch" jako "pozostaje w promieniu pikseli x dla n ms".

Subskrybuj zdarzenie MouseMove i użyj licznika czasu (ustawionego na n ms), aby ustawić limit czasu. Za każdym razem, gdy mysz się porusza, sprawdź zgodność z tolerancją. Jeśli jest poza tolerancją, zresetuj licznik i zapisz nowe źródło.

Pseudokod:

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

Dzięki, spróbuję tego. :) –

+0

Skończyło się na robieniu czegoś znacznie prostszego przy użyciu timera. To trochę "hackish", ale robi to zadanie. Dzięki za pomoc. –

+0

@lc: Mam podobną implementację, ale nie znalazłem konieczności używania "tolerancji". Sprawdzenie, czy ostatnia lokalizacja myszy jest inna niż bieżąca, działa dobrze. –

2

Dlaczego nie zapisać się do wydarzeń mouseMove w przypadku MouseHover, a następnie wypisać w przypadku mouseLeave

Edit:

Jednym ze sposobów, aby sprawdzić, czy mysz jest zatrzymany byłoby uruchomić czasomierz za każdym razem uzyskać ruch myszy, gdy upłynął czas, można rozważyć zatrzymanie myszy. Przyczyna usunięcia zdarzeń MouseMove w MouseLeave umożliwiłaby odbieranie zdarzeń tylko wtedy, gdy mysz jest nad kontrolą.

+0

Czy możesz wyjaśnić, co masz na myśli? Obsługuję już zdarzenie MouseMove i informuje mnie tylko kiedy mysz się porusza, a nie kiedy jest zatrzymana. –

+0

Heh. Ten sam pomysł. +1 –

+0

Myślałem o użyciu timera. Spróbuję tego jutro. I nie mogę używać drugiej opcji, ponieważ potrzebuję odbierać zdarzenia myszy, nawet gdy mysz znajduje się poza kontrolą. –

5

Zdaję sobie sprawę, że jest to stary temat, ale chciałem podzielić sposób znalazłem to zrobić: na ResetMouseEventArgs wywołania zdarzenia ruch myszy() na kontrolę, która łapie imprezę .

+2

To nie działa dla mnie. – snarf

1

To była najczystsza implementacja, jaką mogłem wymyślić. Działa całkiem dobrze:

[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

Oto nieco prostsza wersja, która nie polega na zegarku. Wystarczy nagrać czas ostatniego ruchu myszy, aby porównać bieżący czas, gdy chcesz sprawdzić, czy mysz jest unoszona.

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

Lub naprawdę krótka wersja, która nie ma tolerancji odległości.

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

Po prostu użyj, jeśli (IsHovering()) ... kiedy musisz sprawdzić, czy mysz się porusza.

Jedną z rzeczy, które zauważyłem jest to, że MouseMove nie jest uruchamiany podczas przeciągania. Możesz jednak skopiować kod myszy mouseMoveTime/Loc do zdarzenia przeciągania, aby obejść to.

Powiązane problemy