Рисование линий мышью
Пример в этом разделе демонстрирует, как следить за курсором мыши. Он содержит части оконной процедуры, которая дает возможность пользователю рисовать линии в рабочей области окна путем перетаскивания мыши.
Когда оконная процедура получает сообщение WM_LBUTTONDOWN, она захватывает мышь и сохраняет координаты курсора, используя их как отправную точку линии. Она также использует и функцию ClipCursor, чтобы ограничить курсор рабочей областью в ходе операции рисования линии.
Во время первого сообщения WM_MOUSEMOVE, оконная процедура рисует линию от отправной точки до текущей позиции курсора. В ходе последующих сообщений WM_MOUSEMOVE, оконная процедура стирает предыдущую линию, рисуя по ней инвертированным цветом пера. Затем она рисует новую линию от отправной точки до новой позиции курсора.
Сообщение WM_LBUTTONUP подает сигнал о конце операции рисования. Оконная процедура освобождает захват мыши и освобождает мышь от ограничения рабочей областью.
Демонстрационный пример
LRESULT APIENTRY MainWndProc(HWND hwndMain, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
HDC hdc; // дескриптор контекста устройства
RECT rcClient; // прямоугольник рабочей области
POINT ptClientUL; // верхний левый угол рабочей области
POINT ptClientLR; // нижний правый угол рабочей области
static POINTS ptsBegin; // исходная точка
static POINTS ptsEnd; // новая конечная точка
static POINTS ptsPrevEnd; // предыдущая конечная точка
static BOOL fPrevLine = FALSE; // флажок предыдущей линии
switch (uMsg)
{
case WM_LBUTTONDOWN:
// Захват ввода данных от мыши.
SetCapture(hwndMain);
// Получим экранные координаты рабочей области,
// и преобразуем их в рабочие координаты.
GetClientRect(hwndMain, &rcClient);
ptClientUL.x = rcClient.left;
ptClientUL.y = rcClient.top;
// Добавим по единице с правой и нижней стороны, поскольку
// координаты полученные при помощи GetClientRect не
// включают в себя крайний левый и крайний нижний пиксели.
ptClientLR.x = rcClient.right + 1;
ptClientLR.y = rcClient.bottom + 1;
ClientToScreen(hwndMain, &ptClientUL);
ClientToScreen(hwndMain, &ptClientLR);
// Скопируем рабочие координаты рабочей области в
// член rcClient структуры. Ограничим курсор мыши рабочей
// областью с помощью передачи rcClient структуры в
// функцию ClipCursor.
SetRect(&rcClient, ptClientUL.x, ptClientUL.y,
ptClientLR.x, ptClientLR.y);
ClipCursor(&rcClient);
// Преобразуем координаты курсора в структуру POINTS,
// которая определяет исходную точку рисуемой линии
// в ходе сообщения WM_MOUSEMOVE.
ptsBegin = MAKEPOINTS(lParam);
return 0;
case WM_MOUSEMOVE:
// Когда мышь движется, пользователь, чтобы нарисовать линию,
// должен удерживать нажатой левую кнопку мыши.
if (wParam & MK_LBUTTON)
{
// Получим контекст устройства (DC) для рабочей области.
hdc = GetDC(hwndMain);
// Ниже следуют функции гарантирующие, что пиксели
// предыдущей нарисованной линии установятся в белый и
// те же самые новой линии установятся в черный.
SetROP2(hdc, R2_NOTXORPEN);
// Если линия была нарисована раньше сообщения WM_MOUSEMOVE
// то рисование проходит поверх ее. Линия стирается при помощи
// установки ее пикселей в белый цвет.
if (fPrevLine)
{
MoveToEx(hdc, ptsBegin.x, ptsBegin.y,
(LPPOINT) NULL);
LineTo(hdc, ptsPrevEnd.x, ptsPrevEnd.y);
}
// Преобразуем текущие координаты курсора в структуру
// POINTS, а затем нарисуем новую линию.
ptsEnd = MAKEPOINTS(lParam);
MoveToEx(hdc, ptsBegin.x, ptsBegin.y, (LPPOINT) NULL);
LineTo(hdc, ptsEnd.x, ptsEnd.y);
// Установим флажок предыдущей линии, сохраним конечную
// точку новой линии, а затем восстановим прежний DC.
fPrevLine = TRUE;
ptsPrevEnd = ptsEnd;
ReleaseDC(hwndMain, hdc);
}
break;
case WM_LBUTTONUP:
// Пользователь закончил рисовать линию. Сбросим флажок
// предыдущей линии, освободим курсор мыши, и освободим
// мышь от захвата.
fPrevLine = FALSE;
ClipCursor(NULL);
ReleaseCapture();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Обработка других сообщений.
|