Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Обработка сообщений о нажатии кнопки мыши




 

Шаг 10. Создание обработчика нажатия кнопки мыши.

Если пользователь нажимает ЛКМ в клиентской области окна приложения, значит, он собирается рисовать, не так ли? Логично считать, что это первое нажатие задает начальную точку фигуры и ее координаты (в пикселах) мы запишем в переменную Anchor, которую мы заблаговременно описали в классе вид. При помощи мастера создайте обработчик сообщения WM_LBUTTONDOWN (не забудьте выбрать класс CPainterView на вкладке ClassView). Код обработчика отредактируйте следующим образом:

 
 

Как Вы догадались, в параметре point в обработчик передаются координаты местоположения мыши в момент нажатия ЛКМ. Эти координаты привязаны к окну вида: координата (0,0) соответствует левому верхнему углу окна вида. Никогда не удаляйте обработчик нажатия кнопки по умолчанию CView::OnLButtonDown(nFlags, point); – он все-таки не лишний и выполняет свою работу.

 

Рисование

 

Шаг 11. Рисование линий.

Если пользователь нажимает ЛКМ и тем самым задает положение начальной точки фигуры, а затем перемещает мышь и отпускает кнопку, задавая положение конечной точки, то программа должна нарисовать нужную фигуру и растянуть ее от начальной до конечной точки.

Начнем с рисования линий – в этом случае, как Вы помните, должен быть установлен флаг bLineFlag. Линия должна рисоваться при отпускании кнопки мыши, поэтому добавьте в программу обработчик сообщения WM_LBUTTONUP с помощью мастера так же, как Вы это уже проделывали для сообщения WM_LBUTTONDOWN на предыдущем шаге. Так как при отпускании ЛКМ пользователь задает положение конечной точки линии, мы должны начать с запоминания координат этой точки в переменной (поле класса) DrawTo:

 
 

Казалось бы, что теперь мы должны собственно выполнить рисование линии, т.е. передать куда-нибудь координаты линии, выполнить собственно рисование и вызвать функцию Invalidate() для того, чтобы обновить содержимое окна вида с помощью метода OnDraw(). Если при этом учесть, что до рисования данной линии пользователь уже мог нарисовать множество других фигур, то надо все это рисование повторить в методе OnDraw() или в других методах. Но для этого, очевидно, надо завести себе структуры данных, в которых будет запоминаться информация обо всех нарисованных пользователем фигурах.

Одним из методов решения этой проблемы может быть применение метафайлов Windows. Кроме того, воспользуемся классом CClientDC для получения контекста устройства в любом методе, а не только в методе OnDraw(), куда он передается в качестве параметра. Этот класс является производным от CDC и позволяет просто получить контекст устройства, передав конструктору класса указатель на текущий объект класса вида:

CClientDC * pDC = new CClientDC(this);

 

Вспомним, что this в методе класса является указателем на объект класса, вызвавший данный метод. Если мы употребляем this в методе класса вид, то мы как раз и получаем указатель на объект класса вид. Теперь указатель pDC мы можем использовать в любом методе класса вид так же, как мы используем этот указатель в методе OnDraw().

Учитывая сказанное, нарисовать линию в методе CPainterView::OnLButtonUp() можно так:

 
 

Обратите внимание, что перед рисованием линии мы проверяем соответствующий флаг, в данном случае bLineFlag.

Если теперь Вы запустите приложение на выполнение, то сможете рисовать линии. Проверьте! Проверьте так же и то, что все Ваши труды по рисованию полностью теряются, если окно перерисовывается, например, перекрывается другим окном.

Шаг 12. Рисование прямоугольников.

Очевидно, что для рисования прямоугольника достаточно несколько изменить код метода OnLButtonUp():

 
 

Запустите теперь приложение на выполнение, нарисуйте линию, затем нарисуйте прямоугольник, частично перекрывающий линию. Вы заметите, что линия под прямоугольником исчезла, была стерта. Для того чтобы избежать этого эффекта, надо для прямоугольника выбрать в качестве текущей пустую кисть:

pDC->SelectStockObject(NULL_BRUSH);

 

Модифицируйте метод OnLButtonUp(), постройте приложение и протестируйте его: теперь прямоугольники не должны затирать другие изображения.

Шаг 14. Заливка фигур.

Для заливки внутреннего контура замкнутой фигуры сплошным цветом можно воспользоваться методом FloodFill(). Для заливки замкнутой области надо указать какую-либо точку внутри этой области и задать цвет границы. Метод FloodFill() заливает фигуру текущей выбранной кистью в качестве которой мы воспользуемся кистью BLACK_BRUSH.

Теперь мы уже можем доработать метод OnLButtonUp(), добавив в него, например, после рисования прямоугольника, следующий очевидный код:

 

Третий параметр FloodFill() – это цвет границы замкнутой области. Тестируйте приложение.

 

Шаг 15. Рисование фигур произвольной формы.

Для рисования фигуры произвольной формы надо отслеживать перемещение мыши, получать последовательность координат точек и соединять эти точки прямыми линиями. Так как количество сообщений о перемещении мыши в секунду ограничено, мы не будем получать сообщение при каждом перемещении мыши на один пиксель. А поэтому если просто закрашивать каждый текущий пиксель, то мы получим последовательность отдельных точек, а не линию.

Рисование фигуры произвольной формы выглядит так: при нажатии ЛКМ запоминается положение начальной точки. Когда мышь перемещается в новую точку, мы рисуем линию от начальной точки до текущей и запоминаем текущую точку в качестве начальной для следующего перемещения мыши.

С помощью мастера добавьте обработчик перемещения мыши OnMouseMove() и подготовьте в нем контекст устройства:

 

Затем необходимо убедиться в том, что в текущем режиме мы должны действительно рисовать фигуру произвольной формы, т.е. проверить флаг bDrawFlag. Кроме того, рисование должно происходить только при нажатой ЛКМ. Проверить этот факт можно путем проверки значения параметра nFlags. Если в nFlags присутствует значение константы MK_LBUTTON, то ЛКМ нажата.

 

Замечание. Параметр nFlags может содержать и другие значения или их комбинации: MK_RBUTTON для ПКМ, MK_MBUTTON для средней клавиши мыши, MK_CONTROL для клавиши Ctrl и MK_SHIFT для клавиши Shift.

 

С учетом сказанного метод OnMouseMove() должен содержать такой код:

 

Тестируйте программу и попробуйте рисовать фигуры произвольной формы. Получилось? Если нет, замените строку

pDC->LineTo(DrawTo.x, DrawTo.y);

на

pDC->LineTo(point.x, point.y);

 

Растягивание фигур

 

В «настоящих» графических редакторах пользователь может растягивать мышью создаваемую фигуру, что позволяет следить за ее контуром во время создания. Добавим и мы такую возможность в нашу программу. Начнем с растягивания прямых линий.

 

Шаг 16. Растягивание линий.

Очевидно, что код растягивания надо включать в обработчик перемещения мыши OnMouseMove(). Чтобы нарисовать линию новой длины и/или в ее новом положении надо выполнить два действия: стереть старое изображение линии от начальной точки к предыдущей и нарисовать новую линию от начальной точки к текущему положению указателя мыши.

Чтобы иметь возможность стереть старую линию, надо запоминать ее положение, для чего мы заблаговременно добавили в программу член класса OldPoint. При нажатии ЛКМ необходимо занести в OldPoint текущие координаты мыши. Для этого необходимо добавить в обработчик OnLButtonDown() операторы:

OldPoint.x=point.x; OldPoint.y=point.y; // или OldPoint=point;

 

Чтобы стереть линию от точки Anchor до точки OldPoint, лучше всего выбрать в контексте устройства бинарный растровый режим R2_NOT и снова нарисовать ту же линию. Что это значит? Бинарный растровый режим управляет тем, как будут выглядеть результаты рисования на экране. Всего таких режимов 16 и R2_NOT – один из них. Включение этого режима приводит к выводу пикселя, цвет которого является инвертированным цветом соответствующего пикселя экрана. Перед установкой нового бинарного режима надо запомнить текущий режим с тем, чтобы потом его восстановить. С учетом сказанного код метода OnMouseMove() должен стать таким:

Тестируйте программу. Обратили внимание, что над черным объектом линия при растягивании выводится белым цветом?

Шаг 17. Растягивание прямоугольников.

Код для выполнения этих операций подобен коду растягивания линий:

Опять-таки, тестируйте программу. Все работает? А если попробовать свернуть окно с рисунком и вновь его развернуть, что случится с изображением. Оно потеряется навеки! Обидно, да?

 

Обновление изображения

Метафайлом называется хранящийся в памяти объект, поддерживающий собственный контекст устройства. Любые операции, выполняемые с контекстом устройства, можно продублировать в метафайле. Если в дальнейшем потребуется повторить действия, выполненные пользователем (например, при обновлении изображения), достаточно воспроизвести данный метафайл. В результате такого воспроизведения все графические операции повторяются и изображение восстанавливается.

Шаг 18. Описание и инициализация класса метафайл.

Указатель на контекст устройства для метафайла CMetaFileDC имеет смысл описать в классе документа СPainterDoc. Для этого в заголовочный файл PainterDoc.h добавьте описание указателя:

// PainterDoc.h: interface of the CPainterDoc class

// …

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...