Режим рисования задает операцию над битами обеих последовательностей, выполняемую в процессе переноса изображения. Всего возможно 16 различных режимов рисования:
Перо (Pen) P | 1 1 0 0 | Выполняемая | Режим рисования |
Имеющееся изображение (Destination)D | 1 0 1 0 | операция | |
0 0 0 0 | 0 | 0 R2_BLACK | |
0 0 0 1 | ~ (P|D) | 1 R2_NOTMERGEPEN | |
0 0 1 0 | (~P)&D | 2 R2_MASKNOTPEN | |
0 0 1 1 | ~P | 3 R2_NOTCOPYPEN | |
0 1 0 0 | P& (~D) | 4 R2_MASKPENNOT | |
0 1 0 1 | ~D | 5 R2_NOT | |
Повторное рисование восстанавливает фон | 0 1 1 0 | P^D | 6 R2_XORPEN |
0 1 1 1 | ~ (P&D) | 7 R2_NOTMASKPEN | |
1 0 0 0 | P&D | 8 R2_MASKPEN | |
1 0 0 1 | ~ (P^D) | 9 R2_NOTXORPEN | |
Прежнее изображение не меняется | 1 0 1 0 | D | 10 R2_NOP |
1 0 1 1 | (~P)|D | 11 R2_MERGENOTPEN | |
Режим рисования по умолчанию | 1 1 0 0 | P | 12 R2_COPYPEN |
1 1 0 1 | P| (~D) | 13 R2_MERGEPENNOT | |
1 1 1 0 | P|D | 14 R2_MERGEPEN | |
1 1 1 1 | 1 | 15 R2_WHITE |
Так, например, по умолчанию используется операция копирования исходного изображения на контекст устройства (называемая R2_COPYPEN), довольно часто применяется операция исключающее или (R2_XORPEN) между пером и существующим изображением на контексте.
Если монохроматические переносимое изображение и уже имеющееся рассматривать как битовые последовательности, то возможны 4 случая:
оба изображения, переносимое (pen) и имеющееся (destination), содержат светлые точки
переносимое изображение (pen) содержит светлую точку, а имеющееся (destination) — темную
переносимое изображение (pen) содержит темную точку, а имеющееся (destination) — светлую
оба изображения, переносимое (pen) и имеющееся (destination), содержат темные точки
Говоря в терминах битов может понадобиться комбинировать 1 с 1, 1 с 0, 0 с 1 и 0 с 0. Эти четыре варианта перечислены во втором столбце таблицы в заголовке. В строчках ниже дается ожидаемый результат во всех четырех случаях.
Например, если в результате комбинирования светлой со светлой должна получиться светлая точка (1 и 1 дает 1), а в остальных случаях — темная (1 и 0, 0 и 1, а также 0 и 0 дают 0), то в таблице эта операция будет обозначена как 1 0 0 0 — R2_MASKPEN.
Вы можете установить желаемый режим рисования, или узнать текущий с помощью функций
intSetROP2 (hDC, nIndex);
intGetROP2 (hDC);
В описании этих функций можно также найти символические имена всех 16 режимов и их краткое описание. Однако, следуя приводимому в документации описанию, найти нужную операцию может быть затруднительно (обычно там не приводятся результаты выполнения операций, только названия и обозначения). В этом случае вы можете получать нужный номер растровой операции из этой таблички, даже вы вообще можете обойтись без символических имен, просто рассматривая битовую последовательность в табличке как номер режима. Этим правилом можно пользоваться, если порядок четырех возможных комбинаций соответствует приведенному в таблице и в примере.
Например, вы хотите выбрать такой режим, что бы изображение получало светлую точку только в том случае, когда и рисуемая точка и точка имеющегося фона имеют темный цвет, или когда точка линии — светлая, а фона — темная; во всех остальных случаях должна получиться темная точка.
Рисунок 6. Получение номера растровой операции.
Для задания дуги, которую вы хотите нарисовать необходимо определить эллипс, дугу которого вы собираетесь нарисовать, а также начальную и конечную точки дуги. Но вот проблема — от начальной до конечной точки можно провести дугу в двух разных направлениях, так что приходится дополнительно определять, в каком именно направлении дуга будет нарисована. Обычно принято, что дуга рисуется против хода часовой стрелки.
Вы можете при необходимости узнать или изменить направление рисования дуг с помощью функций:
int GetArcDirection (hDC);
int SetArcDirection (hDC, nIndex);
Допустимыми являются AD_COUNTERCLOCKWISE — рисование против хода часовой стрелки (принято по умолчанию) и AD_CLOCKWISE — по ходу часовой стрелки.
Внимание! Эти две функции не работают в случае расширенного режима задания координат (см. функцию SetGraphicsMode1, GM_ADVANCED) — в этом случае дуги всегда рисуются против хода часовой стрелки.
Дополнительные средства для рисования линий
Windows содержит еще одну функцию, которая применяется для рисования линий. Она предназначена для последовательного вычисления координат точек, принадлежащих линии, и выполнения над этими точками какой-либо операции, определенной пользователем. Фактически эта функция для каждой точки рисуемой линии вызывает указанную пользователем процедуру. Любопытно, что сама эта функция никак не взаимодействует с контекстом устройства, она выполняет только математические операции, вычисляя все промежуточные точки линии.
void LineDDA (nXStart, nYStart, nXEnd, nYEnd, lpfnDdaPrc, lParam);
nXStart, nYStart — определяют первую точку линии
nXEnd, nYEnd — определяют последнюю точку линии
lpfnDdaPrc — указатель на процедуру типа LINEDDAPROC
lParam — данные, передаваемые пользователем процедуре LINEDDAPROC
Вызываемая процедура LINEDDAPROC имеет следующий вид:
void CALLBACK LineDDAproc (nX, nY, lParam) {
// ...}
Процедура LineDDAproc получает координаты точки, которую надо нарисовать и данные, переданные пользователем.
Координаты первой и последней точек задаются в произвольных единицах, так как их использование определяется не процедурой LineDDA, а процедурой LineDDAproc, разрабатываемой вами. Какие координаты вам удобнее — такие и используйте. Адрес процедуры lpfnDdaPrc в случае WindowsAPI является адресом, возвращаемом функцией MakeProcInstance, но не адресом самой процедуры (об этом подробнее — в разделе «диспетчер памяти»). Данные, передаваемые пользователем, (lParam) являются двойным словом. В документации утверждается, что это дальний указатель на данные, хотя это некорректное утверждение. Часто параметр в виде двойного слова используется для задания адреса каких–либо данных (особенно, если данные занимают больше двух слов), однако реально там может удерживаться произвольное 32х разрядное число. Более того, в прототипе функции он описан именно как long.
Рисование заполненных фигур
Следующая группа функций предназначена для отображения заполненных фигур. К таким фигурам относятся прямоугольники, прямоугольники со скругленными краями, эллипсы, сектора, дуги, стянутые хордой и многоугольники. Условно можно представить себе рисование заполненных фигур как процесс, состоящий из двух этапов — рисование контура текущим пером и заполнение фона. При рисовании контура справедливы все замечания, сделанные при обсуждении рисования линий. Если вам не надо рисовать контур, то выберите в контекст устройства прозрачный карандаш (функция GetStockObject или макрос GetStockPen, NULL_PEN). При заполнении фона рисуемой фигуры используются как уже рассмотренные атрибуты GDI, так и несколько новых. Естественно, что перед рисованием нужной вам фигуры вы должны установить требуемые значения атрибутов контекста устройства.
Кисть (Brush).
Кисть используется как для закраски внутренней области замкнутых фигур, так и для закраски внутренней области окна. Если фон фигуры заполнять не надо, то установите прозрачную кисть. Фактически кисть представляет собой маленький, 8x8 пиксель битмап, который многократно повторяется при заполнении указанной области. Кисть может быть как однотонной (все точки кисти имеют одинаковый цвет), так и штрихованной или узорчатой. Для штрихованных кистей определяется только цвет штрихов; цвет промежутков между штрихами определяется непосредственно при закраске области.
Цвет фона (Background Color).
При закраске областей штрихованными кистями, кисть определяет только лишь цвет штрихов, а промежутки между штрихами заполняются текущим цветом фона.
Режим заполнения фона (Background Mode).
Определяет, надо–ли закрашивать промежутки между линиями штрихованных кистей цветом фона или оставить фон без изменений.
Режим рисования (Drawing Mode).
Определяет операцию, выполняемую в процессе переноса формируемого изображения на контекст устройства.
Направление рисования эллипсов (Arc Direction).
Влияет на способ задания начальной и конечной точек дуг, образующих сектора или дуги, стянутые хордой.
Режим заполнения многоугольников (Polygon Filling Mode).
При рисовании заполненных многоугольников вы можете задать многоугольник такой формы, что он будет содержать накладывающиеся друг на друга элементы. GDI предлагает два разных алгоритма, вычисляющих конфигурацию закрашиваемой области. С помощью данного атрибута вы можете выбрать более подходящий вам алгоритм.
Большинство перечисленных здесь атрибутов GDI уже рассмотрено в разделе «Рисование линий», так что повторно обсуждаться они не будут. Ниже отдельно вынесено обсуждение двух новых атрибутов: кисть и режим заполнения многоугольников.
Функции для рисования заполненных фигур
Среди всех функций, рисующих заполненные объекты, можно условно выделить группу функций, для выполнения которых вы должны задать описывающий рисуемый объект прямоугольник. К таким функциям относятся функции по рисованию прямоугольника (Rectangle), прямоугольника со скругленными краями (RoundRect), эллипса (Ellipse), а также функции для рисования сектора (Pie) и дуги, стянутой хордой (Chord). Все эти функции требуют задания либо непосредственно рисуемого прямоугольника, либо прямоугольника, в который будет вписан рисуемый объект (прямоугольник со скругленными углами, весь рисуемый эллипс или эллипс, дуга которого используется для рисования сектора или стягивается хордой).
При задании описывающего прямоугольника необходимо учитывать несколько нюансов: