Работа с мышкой - Рисование линий при помощи мышки
ОГЛАВЛЕНИЕ
Рисование линий при помощи мышки
В данном разделе статьи представлена часть кода оконной процедуры, которая позволяет пользователю рисовать линии в клиентской области окна путём перетаскивания мышки.
Когда оконная процедура получает сообщение 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;
// Обрабатываем другие сообщения.