Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

93

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

Рис. 4.15 Окно программы BEZIER

Функция PoliBezierTo использует текущее положение пера как начальную точку. Первый и все последующие сплайны требуют только три точки. Когда функция возвращает управление, текущая позиция пера устанавливается в конечную точку последней кривой.

Одно предупреждение: Когда вы рисуете набор связанных сплайнов Безье, в точке связи будет плавный переход, только если вторая контрольная точка первой кривой Безье, конечная точка первой кривой (она же начальная точка второй кривой) и первая контрольная точка второй кривой лежат на одной прямой.

Использование стандартных перьев

Когда вы вызываете одну из функций рисования кривых, которые только что рассматривались, Windows для рисования линии использует перо, выбранное в контексте устройства в данный момент. Перо определяет цвет линии, ширину и ее стиль, который может быть сплошным (solid), точечным (dotted) или пунктирным (dashed). Перо, устанавливаемое в контексте устройства по умолчанию называется BLACK_PEN (черное перо, черный карандаш). Это перо рисует сплошные черные линии толщиной в один пиксель независимо от режима отображения (mapping mode). BLACK_PEN — это одно из трех "стандартных" перьев, поддерживаемых Windows. Два других — это WHITE_PEN (белое перо) и NULL_PEN (пустое перо). NULL_PEN это перо, которое ничего не рисует. Вы можете также создавать свои собственные перья.

В программах для Windows обычно для ссылки на перо используется описатель (handle). Заголовочный файл Windows содержит определение типа HPEN, описатель пера (handle to a pen). Вы можете определить переменную, например, hPen, используя такое определение:

HPEN hPen;

Вы получаете описатель одного из стандартных перьев, вызывая функцию GetStockObject. Например, предположим, вы хотите использовать стандартное перо WHITE_PEN. Его описатель можно получить так:

hPen = GetStockObject(WHITE_PEN);

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

SelectObject(hdc, hPen);

После этого вызова все линии, которые вы рисуете, будут использовать WHITE_PEN до тех пор, пока вы не выберете другое перо в контекст устройства или пока не освободите контекст устройства.

Вместо того, чтобы определять переменную hPen, вы можете совместить вызовы GetStockObject и SelectObject в одной инструкции:

SelectObject(hdc, GetStockObject(WHITE_PEN));

Если затем вы захотите вернуться к использованию пера BLACK_PEN, вы можете получить описатель этого стандартного пера и выбрать его в контекст устройства в одной инструкции:

SelectObject(hdc, GetStockObject(BLACK_PEN));

94

SelectObject возвращает описатель того пера, которое уже было выбрано в контексте устройства. Если вы начинаете работать с только что полученным описателем контекста устройства и вызываете:

hPen = SelectObject(hdc, GetStockObject(WHITE_PEN));

то текущим выбранным пером в контексте устройства становится WHITE_PEN, а переменная hPen становится описателем пера BLACK_PEN. Вы можете выбрать BLACK_PEN в контекст устройства, используя вызов:

SelectObject(hdc, hPen);

Создание, выбор и удаление перьев

Хотя перья, определенные как стандартные объекты, несомненно, удобны, вы ограничены использованием только сплошного черного пера, сплошного белого пера или пустого пера. Если вы хотите большего, то вы должны создавать свои собственные перья. Здесь приведена последовательность действий: вы создаете "логическое перо", которое только описывает перо, используя функции CreatePen или CreatePenIndirect. (Вы можете также использовать функцию ExtCreatePen, которая будет обсуждаться далее в этой главе.) Эти функции возвращают описатель логического пера. Вы выбираете перо в контекст устройства путем вызова SelectObject. Затем вы можете рисовать линии, используя это новое перо. Только одно перо может быть одновременно выбрано в контексте устройства. После того, как вы освободите контекст устройства (или выберете в контекст устройства другое перо), вы можете удалить созданное вами перо, используя DeleteObject. После того, как вы это сделаете, значение описателя пера становится недействительным.

Логическое перо — объект GDI. Вы создаете и используете перо, но оно не принадлежит вашей программе. В действительности оно принадлежит модулю GDI. Перо — это один из шести объектов GDI, которые вы можете создавать. Другие пять — это кисти, битовые образы, регионы, шрифты и палитры. За исключением палитр все эти объекты выбираются в контекст устройства, используя функцию SelectObject.

Три правила управляют использованием таких объектов GDI как перья:

Обязательно удаляйте все созданные вами объекты GDI.

Не удаляйте объекты GDI, пока они выбраны в действительном контексте устройства.

Не удаляйте стандартные объекты.

Это разумные правила, но они иногда могут немного подвести. Рассмотрим на примерах, как действуют эти правила.

Вызов функции CreatePen выглядит так:

hPen = CreatePen(iPenStyle, iWidth, rgbColor);

Параметр iPenStyle определяет, какого типа линии будут отображаться: сплошная, точечная или пунктирная. Этот параметр может принимать одно значение из следующего списка идентификаторов, приведенных в заголовочном файле Windows. На рис. 4.16 показаны линии каждого типа.

PS_SO LID

PS_D ASH

PS_D O T

PS_D ASH DO T

PS_D ASH DO TDO T

PS_N ULL

PS_IN SID EFRAM E

Рис. 4.16 Семь стилей пера

Для стилей PS_SOLID, PS_NULL и PS_INSIDEFRAME параметр iWidth — ширина пера. Ширина iWidth равная 0, заставляет Windows использовать перо шириной в один пиксель. Стандартные перья имеют ширину в 1 пиксель. Если вы зададите точечный или пунктирный стиль линии с физической шириной больше 1, Windows, тем не менее, будут использовать сплошное перо.

95

Параметр rgbColor функции CreatePen — это беззнаковое длинное целое, задающее цвет пера. Для перьев всех стилей, кроме PS_INSIDEFRAME, когда вы выбираете перо в контекст устройства, Windows преобразует значение этого параметра в ближайший чистый цвет, какой может представить устройство. Только перья со стилем PS_INSIDEFRAME могут использовать полутона, и только если их ширина больше 1.

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

Вы можете также создать перо, определив структуру типа LOGPEN — "логическое перо" (logical pen) и вызвав функцию CreatePenIndirect. Если ваша программа использует несколько различных перьев, которые вы инициализируете в своей программе, этот метод наиболее эффективен. В начале вы определяете переменную типа

LOGPEN, например, logpen:

LOGPEN logpen;

Эта структура имеет три члена: lopnStyle (UINT) — стиль пера, lopnWidth (POINT) — ширина пера в логических единицах измерения, lopnColor (COLORREF) — цвет пера. Член структуры lopnWidth имеет тип POINT, но Windows использует только величину lopnWidth.x как ширину пера и игнорирует значение lopnWidth.y. Затем вы создаете перо, передавая адрес структуры в функцию CreatePenIndirect:

hPen = CreatePenIndirect(&logpen);

Вы можете также получить информацию логического пера для уже существующего пера. Если у вас есть описатель пера, вы можете скопировать данные, определяющие логическое перо в структуру типа LOGPEN, используя вызов GetObject:

GetObject(hPen, sizeof(LOGPEN),(LPVOID) &logpen);

Обратите внимание, что функции CreatePen и CreatePenIndirect не требуют описателя контекста устройства. Эти функции создают логические перья, которые никак не связаны с контекстом устройства до тех пор, пока вы не вызовите SelectObject. Например, вы можете использовать одно логическое перо для нескольких различных устройств, таких как дисплей и принтер.

Ниже представлен метод создания, выбора и удаления перьев. Предположим, ваша программа использует три пера

— черное шириной 1, красное шириной 3 и черное точечное. Вы можете сначала определить переменные для хранения описателей этих перьев:

static HPEN hPen1, hPen2, hPen3;

В процессе обработки сообщения WM_CREATE вы можете создать три пера:

hPen1 = CreatePen(PS_SOLID, 1, 0);

hPen2 = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

hPen3 = CreatePen(PS_DOT, 0, 0);

В процессе обработки сообщения WM_PAINT (или в любой момент, когда у вас есть действительный контекст устройства) вы можете выбрать одно из этих перьев в контекст устройства и рисовать, используя его:

SelectObject(hdc, hPen2);

[функции рисования линий]

SelectObject(hdc, hPen1);

[другие функции рисования линий]

В процессе обработки сообщения WM_DESTROY вы можете удалить три пера, созданные вами ранее:

DeleteObject(hPen1);

DeleteObject(hPen2);

DeleteObject(hPen3);

Это наиболее общий, магистральный метод создания, выбора и удаления перьев, но он требует резервирования памяти для логических перьев на все время работы вашей программы. Вместо этого вы можете создать перья в процессе обработки сообщения WM_PAINT и удалить их после вызова EndPaint. (Вы можете удалить их и до вызова EndPaint, но вы должны быть осторожны и не удалить перо, выбранное в контекст устройства.)

Кроме того вы можете создать перья на "лету" и объединить вызовы функций CreatePen и SelectObject в одну инструкцию:

SelectObject(hdc, CreatePen(PS_DASH, 0, RGB(255, 0, 0)));

Теперь, когда вы рисуете линии, вы будете использовать красное точечное перо. Когда вы закончите рисовать красным точечным пером, вы можете удалить его. Но, как можно удалить это перо, если не сохранен его

96

описатель? Новый вызов SelectObject возвращает описатель пера, которое было раньше выбрано в контексте устройства. Таким образом, вы можете удалить перо путем выбора стандартного пера BLACK_PEN в контекст устройства и удаления значения, возвращаемого функцией SelectObject:

DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN)));

Рассмотрим другой метод. Когда вы выбираете только что созданное перо в контекст устройства, сохраните описатель, возвращаемый функцией SelectObject:

hPen = SelectObject(hdc, CreatePen(PS_DASH, 0, RGB(255, 0, 0)));

Что такое hPen? Если это первый вызов SelectObject после получения описателя контекста устройства, то hPen — это описатель стандартного пера BLACK_PEN. Вы можете теперь выбрать это перо в контекст устройства и удалить перо, созданное вами (описатель, возвращаемый вторым вызовом функции SelectObject) в одной инструкции:

DeleteObject(SelectObject(hdc, hPen));

Закрашивание пустот

Использование точечных и штриховых перьев ставит интересный вопрос: что будет с пустотами между точками и штрихами? Цвет этих пробелов или пустот зависит от режима фона (background mode) и атрибутов цвета фона, определенных в контексте устройства. Режим фона по умолчанию равен OPAQUE, т. е. Windows заполняет пустоты цветом фона, который, по умолчанию, белый. Это согласуется с работой стандартной кисти WHITE_BRUSH, которую многие программы используют в классе окна для стирания фона окна.

Вы можете изменить цвет фона, который Windows будет использовать для закрашивания пустот, вызвав:

SetBkColor(hdc, rgbColor);

Также как и для перьев, Windows преобразует этот цвет фона к чистому цвету. Вы можете определить текущий цвет фона, выбранный в контексте устройства, вызвав функцию GetBkColor.

Вы можете также отменить заполнение пустот системой Windows, изменив режим фона на TRANSPARENT:

SetBkMode(hdc, TRANSPARENT);

Windows будет игнорировать цвет фона и не будет заполнять пустоты. Вы можете определить текущий режим фона (как TRANSPARENT, так и OPAQUE), путем вызова GetBkMode.

Режимы рисования

Представление линий, отображаемых на дисплее, зависит также от режима рисования (drawing mode), установленного в контексте устройства. Представление цветной линии основывается не только на цвете пера, но и на цвете той области дисплея, где эта линия отображается. Подумайте о возможности использовать одно и то же перо для рисования черной линии на белом фоне и белой линии на черном фоне без знаний о том, какого цвета фон. Было бы это для вас удобным? Вы можете все проверить, применяя различные режимы рисования.

Когда Windows использует перо для рисования линии, на самом деле осуществляется поразрядная логическая операция между пикселями пера и пикселями принимающей поверхности устройства. Выполняемая поразрядная логическая операция над пикселями носит название "растровой операции" (raster operation или ROP). Поскольку рисование линий требует только двух пиксельных шаблонов (пера и приемной поверхности), логическая операция называется "бинарной растровой операцией" (binary raster operation или ROP2). Windows определяет 16 ROP2 кодов, показывающих, как Windows оперирует с пикселями пера и приемника. В контексте устройства по умолчанию режим рисования определяется как R2_COPYPEN, что означает простое копирование системой Windows пикселей пера в приемник и привычным при работе с перьями. Существует также еще 15 других ROP2 кодов.

Откуда взялись эти 16 различных ROP2 кодов? Для того, чтобы показать зачем они введены, рассмотрим монохромную систему. Цвет приемника (цвет рабочей области окна) может быть либо черным (0) либо белым (1). Перо также может быть либо белым, либо черным. Существует четыре комбинации использования черного или белого пера на черном или белом приемнике: белое перо на белом приемнике, белое перо на черном приемнике, черное перо на белом приемнике и черное перо на черном приемнике.

Что произойдет с приемником после рисования? Один вариант — это линия всегда будет черной, независимо от цвета пера или приемника: Это режим рисования, имеющий один из ROP2 кодов, а именно код R2_BLACK. Другой вариант — это линия будет черной, кроме комбинации, когда и перо и приемник — черные. В этом случае линия будет белой. Хотя это может показаться странным, в Windows есть соответствующий режим рисования, который называется R2_NOTMERGEPEN. Windows выполняет поразрядную операцию OR над пикселями пера и приемника, а затем инвертирует результат.

Соседние файлы в предмете Операционные системы