Compartilhar via


Operações diversas do mouse

As seções anteriores discutiram cliques do mouse e movimento do mouse. Aqui estão algumas outras operações que podem ser executadas com o mouse.

Arrastando elementos da interface do usuário

Se a interface do usuário der suporte ao arrasto de elementos da interface do usuário, há uma outra função que você deve chamar no manipulador de mensagens do mouse para baixo: DragDetect. A função DragDetect retornará TRUE se o usuário iniciar um gesto de mouse que deve ser interpretado como arrastando. O código a seguir mostra como usar essa função.

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

Aqui está a ideia: quando um programa dá suporte a arrastar e soltar, você não quer que cada clique do mouse seja interpretado como um arraste. Caso contrário, o usuário pode arrastar algo acidentalmente quando ele ou ela simplesmente pretendia clicar nele (por exemplo, para selecioná-lo). Mas se um mouse for particularmente sensível, pode ser difícil manter o mouse perfeitamente parado enquanto clica. Portanto, o Windows define um limite de arrastar de alguns pixels. Quando o usuário pressiona o botão do mouse, ele não é considerado um arraste, a menos que o mouse cruze esse limite. A função DragDetect testa se esse limite foi atingido. Se a função retornar TRUE, você poderá interpretar o clique do mouse como um arraste. Caso contrário, não.

Observação

Se DragDetect retornar FALSE, o Windows suprimirá a mensagem WM_LBUTTONUP quando o usuário liberar o botão do mouse. Portanto, não chame DragDetect , a menos que seu programa esteja atualmente em um modo que dê suporte à arrastar. (Por exemplo, se um elemento de interface do usuário arrastável já estiver selecionado.) No final deste módulo, veremos um exemplo de código mais longo que usa a função DragDetect .

 

Limitando o cursor

Às vezes, talvez você queira restringir o cursor à área do cliente ou a uma parte da área do cliente. A função ClipCursor restringe o movimento do cursor a um retângulo especificado. Esse retângulo é fornecido em coordenadas de tela, em vez de coordenadas do cliente, portanto, o ponto (0, 0) significa o canto superior esquerdo da tela. Para converter coordenadas do cliente em coordenadas de tela, chame a função ClientToScreen.

O código a seguir limita o cursor à área do cliente da janela.

    // 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 usa uma estrutura RECT , mas ClientToScreen usa uma estrutura POINT . Um retângulo é definido por seus pontos superior esquerdo e inferior direito. Você pode limitar o cursor a qualquer área retangular, incluindo áreas fora da janela, mas limitar o cursor à área do cliente é uma maneira típica de usar a função. Limitar o cursor a uma região totalmente fora da janela seria incomum, e os usuários provavelmente perceberiam isso como um bug.

Para remover a restrição, chame ClipCursor com o valor NULL.

ClipCursor(NULL);

Eventos de acompanhamento do mouse: focalizar e sair

Duas outras mensagens do mouse são desabilitadas por padrão, mas podem ser úteis para alguns aplicativos:

  • WM_MOUSEHOVER: o cursor passou o mouse sobre a área do cliente por um período fixo de tempo.
  • WM_MOUSELEAVE: o cursor deixou a área do cliente.

Para habilitar essas mensagens, chame a função TrackMouseEvent .

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

A estrutura TRACKMOUSEEVENT contém os parâmetros da função. O membro dwFlags da estrutura contém sinalizadores de bits que especificam em quais mensagens de acompanhamento você está interessado. Você pode optar por obter WM_MOUSEHOVER e WM_MOUSELEAVE, conforme mostrado aqui, ou apenas um dos dois. O membro dwHoverTime especifica por quanto tempo o mouse precisa passar o mouse antes que o sistema gere uma mensagem de foco. Esse valor é fornecido em milissegundos. A constante HOVER_DEFAULT significa usar o padrão do sistema.

Depois de receber uma das mensagens solicitadas, a função TrackMouseEvent será redefinida. Você deve chamá-lo novamente para obter outra mensagem de acompanhamento. No entanto, você deve aguardar até a próxima mensagem de movimentação do mouse antes de chamar TrackMouseEvent novamente. Caso contrário, sua janela poderá ser inundada com mensagens de rastreamento. Por exemplo, se o mouse estiver passando o mouse, o sistema continuará gerando um fluxo de mensagens WM_MOUSEHOVER enquanto o mouse estiver parado. Na verdade, você não quer outra mensagem WM_MOUSEHOVER até que o mouse se mova para outro local e passe o mouse novamente.

Aqui está uma classe auxiliar pequena que você pode usar para gerenciar eventos de rastreamento de mouse.

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

O exemplo a seguir mostra como usar essa classe no procedimento de janela.

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

Os eventos de rastreamento do mouse exigem processamento adicional pelo sistema, portanto, deixe-os desabilitados se você não precisar deles.

Para integridade, aqui está uma função que consulta o sistema para o tempo limite de foco padrão.

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

Botão de rolagem do mouse

A função a seguir verifica se uma roda do mouse está presente.

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

Se o usuário girar a roda do mouse, a janela com foco receberá uma mensagem WM_MOUSEWHEEL . O parâmetro wParam dessa mensagem contém um valor inteiro chamado delta que mede até que ponto a roda foi girada. O delta usa unidades arbitrárias, em que 120 unidades são definidas como a rotação necessária para executar uma "ação". É claro que a definição de uma ação depende do programa. Por exemplo, se a roda do mouse for usada para rolar texto, cada 120 unidades de rotação rolará uma linha de texto.

O sinal do delta indica a direção da rotação:

  • Positivo: gire para frente, longe do usuário.
  • Negativo: gire para trás, em direção ao usuário.

O valor do delta é colocado em wParam junto com alguns sinalizadores adicionais. Use a macro GET_WHEEL_DELTA_WPARAM para obter o valor do delta.

int delta = GET_WHEEL_DELTA_WPARAM(wParam);

Se a roda do mouse tiver uma alta resolução, o valor absoluto do delta poderá ser menor que 120. Nesse caso, se fizer sentido a ação ocorrer em incrementos menores, você poderá fazer isso. Por exemplo, o texto pode rolar por incrementos de menos de uma linha. Caso contrário, acumule o delta total até que a roda gire o suficiente para executar a ação. Armazene o delta não utilizado em uma variável e, quando 120 unidades forem acumuladas (positivas ou negativas), execute a ação.

Avançar

Entrada por teclado