Окт 16

Рисуем мышью

В любом графическом редакторе, как правило, предусмотрена возможность рисовать линии произвольной формы с помощью мыши. Пользователь устанавливает курсор на начальную точку линии, нажимает левую кнопку мыши и, не отпуская кнопку, перемещает мышь, рисуя прямые, кривые и другие замысловатые линии. Рисование линии заканчивается, когда левая кнопка отпускается.
Процесс рисования очередной линии начинается с нажатия левой кнопки мыши. Программа, обрабатывая сообщение WM_LBUTT0ND0WN, устанавливает флаг слежения за мышью bTracking в значение TRUE и задает начальную позицию пера при помощи функции MoveToEx. После этого при обработке сообщения WM_M0USEM0VE программа просто проводит линию в текущую позицию курсора мыши. Когда пользователь отпускает кнопку мыши, флаг bTracking сбрасывается в FALSE и рисование прекращается.
Обратите особое внимание на то, с каким контекстом устройства работают рисующие функции MoveToEx и LineTo. Дескриптор контекста дисплея hDC объявлен со спецификатором static. Это раз. Программа получает контекст устройства при помощи функции GetDC в блоке обработки сообщения WM_CREATE, а освобождает его с помощью ReleaseDC в блоке обработки сообщения WM_DESTROY. Это два. Все это позволяет обновлять клиентскую область непосредственно в ответ на пользовательский ввод информации с помощью мыши, не прибегая к механизмам, генерирующим сообщение WM_PAINT. Иными словами, обеспечивается минимальная задержка между вводом пользователя и реакцией приложения. Статический класс памяти для переменной hDC здесь необходим потому, что требуется сохранять значение атрибута «текущая позиция пера», используемого и модифицируемого функцией LineTo, между двумя последовательными вызовами функции WndProc.
Но что это?.. Как только пользователь пытается изменять размеры окна, ухватившись мышью за его рамку, изображение тотчас бесследно исчезает! Ах, да... Мы же забыли про обработку сообщения WM_PAINT, которое генерируется при изменении размеров окна!
Давайте устраним эту оплошность. Но что же будет рисовать приложение в блоке обработки сообщения WM_PAINT? Ведь информация о траекториях движения мыши нигде не сохранена! Значит, надо где-то сохранять массивы координат позиций мыши для каждой рисуемой линии. Сложность проблемы состоит в том, что количество линий заранее неизвестно, так же как и количество точек в каждой линии может быть произвольным. Таким образом, использование статических массивов будет крайне неудобным.
На выручку в таких ситуациях приходит замечательный класс vector из стандартной библиотеки шаблонов STL. Объект класса vector — это, фактически, динамический массив с переменным размером, обслуживаемый набором удобных для программиста методов. Аналогично классу string класс vector обеспечивает автоматическое управление выделением и освобождением памяти.
Чтобы использовать в программе объекты класса vector, необходимо в начало файла с исходным кодом добавить следующие директивы:
finclude using namespace std;
Класс vector является шаблонным классом, поэтому при объявлении его объекта необходимо указать в угловых скобках имя конкретного типа, как показано ниже:
vector vl; // vl - вектор элементов типа int
Мы, конечно, не будем рассматривать здесь все методы класса vector, а остановимся кратко только на тех, которые нужны для нашей программы.
После объявления вектора vl, приведенного выше, этот вектор пуст, то есть не содержит ни одного элемента. Добавление нового элемента в конец вектора осуществляется при помощи метода push_back:
vl.push_back(value);
Эта инструкция добавляет новый элемент типа int в конец вектора vl и присваивает ему значение переменной value.