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