Рисование линий мышью

Пример в этом разделе демонстрирует, как следить за курсором мыши. Он содержит части оконной процедуры, которая дает возможность пользователю рисовать линии в рабочей области окна путем перетаскивания мыши.

Когда оконная процедура получает сообщение 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; 
 
        // Обработка других сообщений. 
		

Назад в оглавление
На главную страницу

Hosted by uCoz