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