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