Udostępnij za pośrednictwem


Różne operacje myszy

W poprzednich sekcjach omówiono kliknięcia myszy i ruch myszą. Oto kilka innych operacji, które można wykonać za pomocą myszy.

Przeciąganie elementów interfejsu użytkownika

Jeśli interfejs użytkownika obsługuje przeciąganie elementów interfejsu użytkownika, istnieje jedna inna funkcja, którą należy wywołać w procedurze obsługi komunikatów myszy w dół: DragDetect. Funkcja DragDetect zwraca true, jeśli użytkownik inicjuje gest myszy, który powinien zostać zinterpretowany jako przeciąganie. Poniższy kod pokazuje, jak używać tej funkcji.

    case WM_LBUTTONDOWN: 
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            if (DragDetect(m_hwnd, pt))
            {
                // Start dragging.
            }
        }
        return 0;

Oto pomysł: Gdy program obsługuje przeciąganie i upuszczanie, nie chcesz, aby każde kliknięcie myszy było interpretowane jako przeciąganie. W przeciwnym razie użytkownik może przypadkowo przeciągnąć coś, gdy po prostu ma go kliknąć (na przykład, aby go wybrać). Ale jeśli mysz jest szczególnie wrażliwa, trudno jest utrzymać mysz idealnie podczas klikania. W związku z tym system Windows definiuje próg przeciągania kilku pikseli. Gdy użytkownik naciśnie przycisk myszy, nie jest uważany za przeciąganie, chyba że mysz przekroczy ten próg. Funkcja DragDetect sprawdza, czy ten próg jest osiągany. Jeśli funkcja zwróci true, możesz interpretować kliknięcie myszy jako przeciągnięcie. W przeciwnym razie nie.

Nuta

Jeśli dragDetect zwraca FALSE, system Windows pomija komunikat WM_LBUTTONUP, gdy użytkownik zwolni przycisk myszy. W związku z tym nie należy wywoływać DragDetect, chyba że program jest obecnie w trybie obsługującym przeciąganie. (Jeśli na przykład zaznaczono już element interfejsu użytkownika z możliwością przeciągania). Na końcu tego modułu zobaczymy dłuższy przykład kodu, który używa funkcji DragDetect.

 

Ograniczenie kursora

Czasami może być konieczne ograniczenie kursora do obszaru klienta lub części obszaru klienta. Funkcja ClipCursor ogranicza ruch kursora do określonego prostokąta. Ten prostokąt jest podawany we współrzędnych ekranu, a nie współrzędnych klienta, więc punkt (0, 0) oznacza lewy górny róg ekranu. Aby przetłumaczyć współrzędne klienta na współrzędne ekranu, wywołaj funkcję ClientToScreen.

Poniższy kod ogranicza kursor do obszaru klienta okna.

    // Get the window client area.
    RECT rc;
    GetClientRect(m_hwnd, &rc);

    // Convert the client area to screen coordinates.
    POINT pt = { rc.left, rc.top };
    POINT pt2 = { rc.right, rc.bottom };
    ClientToScreen(m_hwnd, &pt);
    ClientToScreen(m_hwnd, &pt2);
    SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);

    // Confine the cursor.
    ClipCursor(&rc);

ClipCursor przyjmuje strukturęRECT, ale ClientToScreen przyjmuje strukturęPUNKT. Prostokąt jest definiowany przez lewy górny i dolny prawy punkt. Kursor można ograniczyć do dowolnego prostokątnego obszaru, w tym obszarów poza oknem, ale ograniczenie kursora do obszaru klienta jest typowym sposobem korzystania z funkcji. Ograniczenie kursora do regionu całkowicie poza oknem byłoby nietypowe, a użytkownicy prawdopodobnie postrzegają go jako usterkę.

Aby usunąć ograniczenie, wywołaj ClipCursor z wartością NULL.

ClipCursor(NULL);

Zdarzenia śledzenia myszy: zatrzymaj wskaźnik myszy i pozostaw

Dwa inne komunikaty myszy są domyślnie wyłączone, ale mogą być przydatne w przypadku niektórych aplikacji:

Aby włączyć te komunikaty, wywołaj funkcję TrackMouseEvent.

    TRACKMOUSEEVENT tme;
    tme.cbSize = sizeof(tme);
    tme.hwndTrack = hwnd;
    tme.dwFlags = TME_HOVER | TME_LEAVE;
    tme.dwHoverTime = HOVER_DEFAULT;
    TrackMouseEvent(&tme);

Struktura TRACKMOUSEEVENT zawiera parametry funkcji. dwFlags element członkowski struktury zawiera flagi bitów, które określają, które komunikaty śledzenia cię interesują. Możesz wybrać zarówno WM_MOUSEHOVER, jak i WM_MOUSELEAVE, jak pokazano tutaj, lub tylko jeden z dwóch. Element członkowski dwHoverTime określa, jak długo mysz musi zatrzymać wskaźnik myszy, zanim system wygeneruje komunikat aktywowania. Ta wartość jest podana w milisekundach. Stała HOVER_DEFAULT oznacza użycie domyślnego ustawienia systemowego.

Po otrzymaniu jednego z żądanych komunikatów funkcja TrackMouseEvent zostanie zresetowana. Należy wywołać go ponownie, aby uzyskać kolejny komunikat śledzenia. Jednak przed ponownym wywołaniem TrackMouseEvent należy zaczekać na następny komunikat przenoszenia myszy. W przeciwnym razie okno może zostać zalane komunikatami śledzenia. Jeśli na przykład wskaźnik myszy jest zatrzymany, system będzie nadal generować strumień komunikatów WM_MOUSEHOVER, gdy mysz jest nieruchoma. Nie chcesz faktycznie innego komunikatu WM_MOUSEHOVER, dopóki mysz nie przeniesie się do innego miejsca i ponownie najecha kursorem.

Oto mała klasa pomocnika, której można użyć do zarządzania zdarzeniami śledzenia myszy.

class MouseTrackEvents
{
    bool m_bMouseTracking;

public:
    MouseTrackEvents() : m_bMouseTracking(false)
    {
    }
    
    void OnMouseMove(HWND hwnd)
    {
        if (!m_bMouseTracking)
        {
            // Enable mouse tracking.
            TRACKMOUSEEVENT tme;
            tme.cbSize = sizeof(tme);
            tme.hwndTrack = hwnd;
            tme.dwFlags = TME_HOVER | TME_LEAVE;
            tme.dwHoverTime = HOVER_DEFAULT;
            TrackMouseEvent(&tme);
            m_bMouseTracking = true;
        }
    }
    void Reset(HWND hwnd)
    {
        m_bMouseTracking = false;
    }
};

W następnym przykładzie pokazano, jak używać tej klasy w procedurze okna.

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_MOUSEMOVE:
        mouseTrack.OnMouseMove(m_hwnd);  // Start tracking.

        // TODO: Handle the mouse-move message.

        return 0;

    case WM_MOUSELEAVE:

        // TODO: Handle the mouse-leave message.

        mouseTrack.Reset(m_hwnd);
        return 0;

    case WM_MOUSEHOVER:

        // TODO: Handle the mouse-hover message.

        mouseTrack.Reset(m_hwnd);
        return 0;

    }
    return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

Zdarzenia śledzenia myszy wymagają dodatkowego przetwarzania przez system, dlatego pozostaw je wyłączone, jeśli ich nie potrzebujesz.

Aby uzyskać kompletność, poniżej przedstawiono funkcję, która wysyła zapytanie do systemu pod kątem domyślnego limitu czasu aktywowania.

UINT GetMouseHoverTime()
{
    UINT msec; 
    if (SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &msec, 0))
    {   
        return msec;
    }
    else
    {
        return 0;
    }
}

Kółko myszy

Poniższa funkcja sprawdza, czy znajduje się koło myszy.

BOOL IsMouseWheelPresent()
{
    return (GetSystemMetrics(SM_MOUSEWHEELPRESENT) != 0);
}

Jeśli użytkownik obraca koło myszy, okno z fokusem otrzymuje komunikat WM_MOUSEWHEEL. Parametr wParam tego komunikatu zawiera wartość całkowitą o nazwie różnicowej, która mierzy, jak daleko koło zostało obracane. Funkcja delta używa dowolnych jednostek, w których zdefiniowano 120 jednostek jako rotację wymaganą do wykonania jednej "akcji". Oczywiście definicja akcji zależy od programu. Jeśli na przykład koło myszy jest używane do przewijania tekstu, każde 120 jednostek obrotu przewija jeden wiersz tekstu.

Znak różnicy wskazuje kierunek obrotu:

  • Dodatnie: obracanie do przodu, z dala od użytkownika.
  • Ujemne: Obracanie do tyłu w kierunku użytkownika.

Wartość różnicy jest umieszczana w wParam wraz z dodatkowymi flagami. Użyj makra GET_WHEEL_DELTA_WPARAM, aby uzyskać wartość różnicy.

int delta = GET_WHEEL_DELTA_WPARAM(wParam);

Jeśli koło myszy ma wysoką rozdzielczość, wartość bezwzględna różnicy może być mniejsza niż 120. W takim przypadku, jeśli ma sens, aby akcja miała miejsce w mniejszych przyrostach, możesz to zrobić. Na przykład tekst może być przewijany przez przyrosty mniejsze niż jeden wiersz. W przeciwnym razie zakumuluj łączną różnicę, aż koło obraca się wystarczająco dużo, aby wykonać akcję. Zapisz nieużywaną różnicę w zmiennej, a gdy 120 jednostek kumuluje się (dodatnie lub ujemne), wykonaj akcję.

Następny

wprowadzanie klawiatury