Глава 9.
Класс поддержки рисования
Мы уже говорили о важности такого понятия, как контекст устройства, и той роли, которую играет класс CDC. В этой главе мне хотелось бы познакомить вас с возможностями, предоставляемыми библиотекой MFC в плане работы с контекстами устройств. Глава несколько выпадает из общего построения книги и носит скорее справочный характер, однако такое решение продиктовано рядом соображений. И основным является то, что в рамках одной книги, какая бы большая она не была, невозможно рассмотреть все вопросы. Например, в разрабатываемом нами приложении "Аналоговые часы" мы коснемся достаточно многих аспектов, связанных с графическим выводом — но, естественно, не всех. Может быть, кто-то из вас в процессе знакомства с кодом найдет решение некоторых проблем, отличающееся от предложенного. Для таких читателей мне хотелось бы дать более широкий обзор возможностей. Другими словами, при последовательном чтении эту главу можно пропустить без ущерба для понимания дальнейшего материала. Итак, начнем.
Рис.9.1.Место класса CDC в иерархии библиотеки MFC
Базовым для всех классов, представляющих в библиотеке MFC контексты устройств, является класс CDC (рис. 9.1). Он предлагает разработчикам набор функций для работы с устройствами, такими как экран дисплея или принтер, а также функций, позволяющих работать с окнами Windows в целом или только с клиентской их частью. Еще раз подчеркну — все операции рисования выполняются только для объектов класса CDC. Из всех классов, предоставляющих интерфейс с контекстами устройств, только этот класс обеспечивает разработчиков всем необходимым для реализации правильного и эффективного графического вывода. Остальные классы, в основном отличающиеся конструктором и деструктором, можно считать вспомогательными.
Система Windows имеет в своем составе, пожалуй, только два вида объектов, число функций для взаимодействия с которыми несоизмеримо с количеством функций для всех других объектов. Речь идет об окнах и контекстах устройств. Естественно, что и библиотека классов MFC обеспечивает соответствующие классы не менее широким набором функций-членов. Об окнах и классе CWnd мы подробно говорили в предыдущих главах, сейчас же проведем обзор функциональных возможностей класса CDC.
Создание объекта класса и его связь с контекстом устройства
Все классы библиотеки MFC, непосредственно связанные с объектами Windows, обеспечивают программиста более удобным и понятным интерфейсом. Часто класс имеет в своем составе конструктор по умолчанию, т. е. без параметров, который только создает объект класса, никак не связанный с объектом Windows. Так как работа с объектами Windows происходит только через дескрипторы, класс должен иметь возможность для их хранения. Рассмотрим упомянутые механизмы и их поддержку в реализации класса CDC.
Класс CDC имеет в своем составе даже не один, а два компонента данных для хранения дескрипторов, что обеспечивает известную гибкость.
HDC CDC::m_hDC
Дескриптор контекста устройства графического вывода.
HDC CDC::m_hAttribDC
Дескриптор контекста устройства, используемый для получения параметров устройства.
По умолчанию m_hDC и m_hAttribDC равны. В принципе контекст устройства вывода m_hDC используется только для выполнения операций рисования, а через второй контекст запрашиваются параметры. Например, функция SetTextColor работает с m_hDC, a GetTextColor — с m_hAttribDC. Однако этот механизм имеет смысл только для объектов класса CMetaFileDC, когда m_hDC настроен на метафайл, a m_hAttribDC настроен на физическое устройство вывода, параметры которого используются для рисования. Аналогичный механизм используется и для режима предварительного просмотра печати (print preview), реализованного в большом количестве приложений. Для этих целей могут применяться функции SetOutputDC и SetAttribDC, которые позволяют приложению связывать объект класса с различными контекстами устройств для графического вывода и получения текущих параметров.
Тем не менее, иногда возникает необходимость получения параметров вывода текста от обоих контекстов. В табл. 9.1 показаны пары функций, используемых в таких случаях.
Таблица 9.1. Примеры пар функций для работы с различными контекстами
m_hAttribDC |
m_hDC |
GetTextExtent |
GetOutputTextExtent |
GetTabbedTextExlent |
GetOutputTabbedTextExtent |
GetTextMetrics |
GetOutputTextMetrics |
GetCharWidth |
GetOutputCharWidth |
Создает объект класса, не связывая его с конкретными контекстами устройств. Для дальнейшей работы необходимо осуществить связывание контекста устройства Windows, который, возможно, следует еще и создать, с объектом класса.
Функции этой группы либо непосредственно создают контексты для конкретных устройств и инициализируют данные класса соответствующими дескрипторами, либо только осуществляют связывание или, наоборот, разрывают связь с существующими контекстами устройств. Из таких функций стоит выделить следующие.
Основная функция создания контекста устройства и инициализации объекта класса CDC — CreateDC.
virtual BOOL CDC::CreateDC (
LPCTSTR IpszDriverName,
LPCTSTR IpszDeviceName,
LPCTSTR IpszOutput, const void* IpInitData;
IpszDriverName — указатель на строку, содержащую имя драйвера, например, "EPSON"; IpszDeviceName — указатель на строку, содержащую имя устройства, например, "EPSON FX-1050" (этот параметр используется, если драйвер фактически поддерживает несколько устройств); IpszOutput— указатель на строку, определяющую собственно приемник — файл, символьное имя устройства или порт вывода; IplnitData — указатель на структуру DEVMODE, содержащую установки устройства; если значение параметра равно NULL, используются установки, заданные в системе по умолчанию.
Примечание
Фирма Microsoft рекомендует имя устройства завершать символом ":", а имена устройств и портов не должны содержать ни ведущих, ни завершающих пробелов. В случае успешного завершения функция возвращает TRUE, иначе FALSE.
virtual BOOL CDC::CreateCompatibleDC (CDC* pDC)
Создает расположенный в памяти контекст устройства, подобный (совместимый) заданному параметром pDC. Такие контексты позволяют выполнять операции рисования без непосредственной визуализации. Если pDC = NULL, функция создает контекст устройства, совместимый с экраном дисплея.
В момент создания контекста GDI автоматически устанавливает для него системный монохромный битовый массив размером 1 пиксел х 1 пиксел. Таким образом, операции графического вывода могут производиться только в том случае, если будет создан и установлен новый битовый массив для данного контекста устройства.
Функция может создать совместимый контекст устройства только для контекстов, поддерживающих растровые операции. Определить, поддерживает устройство растровые операции или нет, можно с помощью функции GetDeviceCaps.
Совместимые контексты используются для улучшения характеристик вывода графических объектов на экран дисплея, т. к. позволяют заранее подготовить "картинку" в памяти, а затем вывести ее полностью на экран, для чего можно воспользоваться функцией BitBlt, осуществляющей перенос битовых массивов между контекстами. Давайте проиллюстрируем это на примере.
void CMercuryFrame::OnPaint()
{
CPaintDC dc(this);
...
// Создание совместимого контекста устройства
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
// Определение размеров клиентской области окна
CRect rect;
GetClientRect(&rect);
// Создание и установка битового массива нужного размера
//и требуемых свойств
CBitmap bitmap, *pBitmap;
bitmap.CreateCo.-rvpatifcleBitmap ;&dc, rect. right, rect.bottom) ;
pBitmap = dcMem.SelectObject(bitmap);
dcMem. Rectangle (...) //- вызов функции рисования
// Копирование содержимого одного контекста в другой
dc.BitBlt(0, 0, rect.right, rect.bottom,
&dcMem., С, О, 3RCCOPY) ;
// Восстановление первоначально созданного ситового массива
if (pBitmap)
dcMem. Select-Object (pBitmap) ;
// Удаление совместимого контекста устройства
dcMem.DeleteDC );
}
Функции с префиксом GetCurrent возвращают указатели на установленные (текущие) графические объекты — карандаши, кисти, битовые массивы, шрифты и палитры:
CPen* CDC: :GetCurrent.Pen ()
CBrush* CDC::GetCurrentBrush ()
CBitmap* CDC: :GetCurrentBitmap ()
CFont* CDC: : GetCurrentFont ()
CPalette* CDC::GetCurrentPaIette ()
Все эти функции могут возвращать указатели на временные объекты соответствующих классов.
Функции этой группы обеспечивают доступ к дескрипторам контекстов (GetSafeHdc), осуществляют сохранение и восстановление параметров контекстов устройств (SaveDC и RestoreDC). К функциям этой группы относится также функция GetDeviceCaps, которая может быть использована для получения исчерпывающей информации о самом устройстве и соответствующем драйвере.
int CDC: : GetDeviceCaps (int nIndex)
Параметр nIndex определяет тип требуемой информации.
Для создания приложения, универсального с точки зрения графического вывода на различные устройства, эту функцию просто необходимо использовать. Различие устройств в поддержке тех или иных возможностей графического вывода может потребовать помощи со стороны GDI или даже самого приложения
Графический вывод можно разделить на две составляющие: вывод текста и вывод графических примитивов. Функции обеих групп используют (и то не всегда) в качестве параметров только координаты вывода. Все остальные параметры, такие как цвет, стиль и т. д., задаются отдельно и действуют до их смены. Поэтому можно задавать параметры вывода сразу для группы последовательно вызываемых функций. Альтернативой такому способу могло бы быть наличие функций со многими параметрами, что затруднило бы сам процесс программирования. Кроме того, при желании всегда можно написать свою функцию, которая в зависимости от параметров, во-первых, осуществляет настройку режима рисования и, во-вторых, производит собственно рисование. Однако в рамках Windows это вряд ли оправданно, т. к. установка ряда параметров рисования осуществляется созданием специальных объектов рисования, максимальное число которых хоть и велико, но ограниченно. Создание таких объектов требует определенных дополнительных расходов, тогда как возможность использования текущих настроек для нескольких функций рисования такие расходы, естественно, снижает.
Класс CDC предоставляет программистам следующие группы функций настройки.
Функции этой группы определяют базовые координаты для закрашивания объектов при помощи текущей установленной кисти (GetBmshOrg и SetBrushOrg) и позволяют получить информацию о системных карандашах и кистях (Enum Objects).
Примечание
Так как кисти представляют собой прямоугольную область размером 8x8 пикселов, закрашивание с их помощью областей большего размера требует определенного согласования, иначе закраска не будет ровной. Например, линии штриховки будут иметь размер небольше 8 пикселов. Для осуществления такого согласования для кистей как раз и определяются базовые координаты.
Функции этой группы используются для установки объектов рисования, определяющих такие параметры рисования, как цвет и стиль линий, вид закрашивания, используемый шрифт и т. д.
Основная функция установки графических объектов — SelectObject. Библиотека MFC в классе CDC определяет пять функций для различных графических объектов:
CPen* CDC::SelectObject (CPen* pPen)
CBrush* CDC::SelectObjecr (CBrush* pBrush)
virtual CFont* CDC::SeiectObject (CFont* pFont;
CBitmap* CDC::SelectObject (CBitmap* pBitmap)
int CDC::SelectObject (CRgn* pRgn)
Все эти функции, за исключением последней, в случае успешной установки возвращают указатель на графический объект соответствующего типа, ранее установленный для контекста устройства, и NULL — в противном случае. Причем указатель может указывать на временный объект и использоваться во время обработки одного сообщения Windows.
Последняя версия функции SelectObject по своему действию аналогична функции SelectClipRgn.
Битовые массивы можно устанавливать только для контекстов устройств в памяти. Причем один битовый массив не может быть установлен одновременно больше, чем для одного такого контекста. Битовый массив может быть либо монохромным, либо совместимым с контекстом устройства, т. е. созданным функцией CBitmap::CreateCompatibleBitmap.
Кроме создаваемых в приложениях графических объектов, существуют и предопределенные системные, которые также можно применять. Для таких объектов следует использовать функцию SelectStockObject, устанавливающую в контексте устройства системные графические объекты различных типов.
virtual CGdiObject* CDC::SelectStockObject (int nlndex)
Возвращает указатели на использованные ранее объекты в случае успешной замены и NULL — в противном случае. Новый объект задается параметром nlndex, имеющим следующие значения:
BLACK_BRUSH
Черная кисть
DKGRAY_BRUSH
Темно-серая кисть
GRAY_BRUSH
Серая кисть
LTGRAY_BRUSH
Светло-серая кисть
HOLLOW_BRUSH
Пустая или прозрачная кисть
NULL_BRUSH
To же, что и HOLLOW_BRUSH
WHITE_BRUSH
Белая кисть
BLACK_PEN
Черный карандаш
NULL_PEN
Пустой или прозрачный карандаш
WHITE_PEN
Белый карандаш
ANSI_FIXED_FONT
Непропорциональный системный шрифт ANSI
ANSI_VAR_FONT
Пропорциональный системный шрифт ANSI
DEVICE_DEFAULT_FONT
Шрифт, зависимый от устройства
OEM_FIXED_FONT
Непропорциональный шрифт OEM
SYSTEM_FONT
Системный шрифт, используемый по умолчанию для отображения пунктов меню, текста элементов управления и т. д.; в версиях Windows, начиная с 3.0, системный шрифт пропорциональный
SYSTEM_FIXED_FONT
Непропорциональный системный шрифт, используется для совместимости с предыдущими версиями Windows
DEFAULT_PALETTE
Основная цветовая палитра, содержащая 20 цветов
Системные кисти DKGRAY_BRUSH, GRAY_BRUSH и LTGRAY_BRUSH могут использоваться только для окон, имеющих стили CS_HREDRAW и CS_VREDRAW. Связано это с тем, что базовые координаты системных кистей не могут настраиваться, и при изменении размеров или положения окон их содержимое может быть испорчено.
Функции настройки цветов и палитр
Функции этой группы позволяют установить новую цветовую палитру (SelectPalette), перерисовать окно, заменяя ранее установленные цвета (UpdateColors), а также создать полутоновую кисть (GetHalftoneBrush), цвет которой получается в результате смешивания текущих цвета фона (background) и цвета, используемого для вывода текстовых строк (foreground).
Функции этой группы используются для настройки различных режимов рисования и закрашивания замкнутых областей. Основные функции мы рассмотрим подробнее, т. к. их значение для реализации графического вывода чрезвычайно важно. Все функции реализованы парами: с префиксом Get — позволяет получить текущее значение параметра, с префиксом Set — устанавливает новое значение и возвращает предыдущее. Далее следует описание наиболее часто используемых функций.
int CDC::SetBkMode (int nBkMode)
Используется для установки режима закрашивания фона. Возможные режимы задаются параметром nBkMode, который может принимать следующие значения:
OPAQUE
(Непрозрачный) фон закрашивается текущим цветом фона при выводе текста, несплошных линий или при использовании штриховых кистей; задано по умолчанию
TRANSPARENT
(Прозрачный) фон не меняется
int CDC::SetPolyFillMode (int nPolyFillMode)
Используется для установки режима закрашивания многоугольников. Возможные режимы задаются параметром nPolyFillMode (рис. 9.2):
ALTERNATE
Режим закрашивания внутренних областей, находящихся между первой и второй, третьей и четвертой и т. д. линиями контура; задан по умолчанию
WINDING
Режим, при котором закрашиваются все внутренние области
Рис. 9.2. Отличие режимов закрашивания: ALTERNATE — слева, WINDING — справа
Для установки режима рисования или заливки используется функция SetROP2. Название функции расшифровывается как "установка режима растровых (пиксельных) операций, использующих в качестве параметров два пиксела". Такими пикселами являются соответствующие друг другу точки экрана и отображаемого объекта.
int CDC::SetROP2 (int nDrawMode)
Возможные режимы задаются параметром nDrawMode, который может принимать следующие значения:
R2_BLACK
Пикселы будут черного цвета
R2_WHITE
Пикселы будут белого цвета
R2_NOP
Пикселы останутся без изменений
R2_NOT
Пикселы будут иметь инверсный по отношению к экрану цвет
R2_COPYPEN
Пикселы будут иметь цвет, заданный для текущего карандаша
R2_NOTCOPYPEN
Пикселы будут иметь инверсный цвет по отношению к цвету текущего карандаша
R2_MERGEPENNOT
Цвет пикселов получается в результате комбинирования цвета карандаша и инверсии цвета экрана ("цвет пиксела" = (NOT "цвет пиксела экрана") OR "цвет карандаша")
R2_MASKPENNOT
Цвет пикселов получается в результате комбинирования цвета карандаша и инверсии цвета экрана ("цвет пиксела" = (NOT "цвет пиксела экрана") AND "цвет карандаша")
R2_MERGENOTPEN
Цвет пикселов получается в результате комбинирования цвета экрана и инверсии цвета карандаша ("цвет пиксела" = (NOT "цвет карандаша") OR "цвет пиксела экрана")
R2_MASKNOTPEN
Цвет пикселов получается в результате комбинирования цвета экрана и инверсии цвета карандаша ("цвет пиксела" = (NOT "цвет карандаша") AND "цвет пиксела экрана")
R2_MERGEPEN
Цвет пикселов получается в результате комбинирования цвета экрана и цвета карандаша ("цвет пиксела" = "цвет карандаша" OR "цвет пиксела экрана")
R2_NOTMERGEPEN
Цвет пикселов получается в результате инверсии R2_MERGEPEN цвета ("цвет пиксела" = МОТ("цвет карандаша" OR "цвет пиксела экрана"))
R2_MASKPEN
Цвет пикселов получается в результате комбинирования цвета экрана и цвета карандаша ("цвет пиксела" = "цвет карандаша" AND "цвет пиксела экрана")
R2_NOTMASKPEN
Цвет пикселов получается в результате инверсии R2_MASKPEN цвета ("цвет пиксела" = NOT("4BeT карандаша" AND "цвет пиксела экрана"))
R2_XORPEN
Цвет пикселов получается в результате комбинирования цвета экрана и цвета карандаша ("цвет пиксела" = "цвет карандаша" XOR "цвет пиксела экрана")
R2_NOTXORPEN
Цвет пикселов получается в результате инверсии R2_XORPEN цвета ("цвет пиксела" = NOT("4eeT карандаша" XOR "цвет пиксела экрана"))
Примечание
Вышеперечисленные режимы рисования линий поддерживаются только растровыми устройствами.
Для выбора режима сжатия битовых массивов используется функция SetStretchBltMode:
int CDC::SetStretchBltMode (int nStretchMode)
Задает режим сжатия/увеличения изображений при использовании функции StretchBIt, в результате выполнения которой возможна потеря фрагментов изображения или их искажение. Возможные режимы задаются параметром nStretchMode, принимающим следующие значения:
STRETCH_ANDSCANS или BLACKONWHITE
Цвет пикселов получается в результате комби-ирования цвета удаляемых пикселов и остающихся с использованием операции AND; для монохромных изображений черные пикселы имеют приоритет над белыми
STRETCH_DELETESCANS или COLORONCOLOR
Режим простого удаления пикселов без попыток сохранить информацию об их цвете
STRETCH_HALFTONE или HALFTONE
При сжатии цвет пикселов результирующего или блока "в среднем" сохраняется
STRETCH_ORSCANS или WHITEONBLACK
Цвет пикселов получается в результате комбинирования цвета удаляемых пикселов и остающихся с использованием операции OR; для монохромных изображений белые пикселы имеют приоритет над черными
К этой же группе относятся функции для назначения и запроса цветов. Одни используются для цвета символов текста (функции SetTextColor и GetTextColor), а другие — для цвета фона (функции SetBkColor и GetBkColor).
Цвет для символов текста используется только в случае, если текстовая строка выводится при помощи функций CDC::TextOut или CDC::ExtTextOut.
Цвет фона используется для заливки промежутков несплошных линий, областей, закрашенных штрихованными кистями, а также просветов между символами текста. Для линий, выведенных с помощью карандашей, созданных с флагами PS_GEOMETRIC или PS_COSMETIC, цвет фона не используется.
До сих пор, говоря о задании координат, мы подразумевали, что речь идет о смещении относительно левого верхнего угла экрана (screen coordinates) или левого верхнего угла клиентской области окна (client coordinates). В принципе, для всего, что касается окон в целом и оконных сообщений, например, WM_MOVE, WM_MOUSEMOVE, это правильно. Однако всегда ли удобно рисовать линию "по точкам", когда, во-первых, все перевернуто с ног на голову — координаты по вертикали растут вниз, во-вторых, приходится постоянно заботиться о масштабе и, в-третьих, приходится помнить формулы вычисления координат точек при повороте и смещении?
Система Windows дает программистам возможность создавать свою собственную систему координат. Для этого, манипулируя различными параметрами, необходимо задать направление и масштаб осей, а также начало координат.
Функции этой группы устанавливают и настраивают систему координат, которая используется всеми функциями вывода: координаты вывода задаются именно в логических единицах. Кроме единиц по осям х и у, функции этой группы задают направление осей и начало координат. Практически все функции реализованы парами: функции с префиксом Get позволяют получить текущее значение параметра, а с префиксом Set устанавливают новое значение и возвращают предыдущее. По умолчанию начало координат находится в левом верхнем углу области вывода (прежде всего окна), ось х направлена слева направо, а ось у — сверху вниз. Единица измерения — один пиксел (режим ММ_ТЕХТ). Кстати сказать, именно поэтому на различных устройствах из-за различий в размерах пиксела фактический (визуальный) размер по оси х может не соответствовать размеру по оси у. Для настройки системы координат Windows использует два понятия — физическая область вывода (viewport), координаты и размеры которой задаются в физических единицах— пикселах, и логическая область вывода (window), координаты и размеры которой задаются в логических единицах, определяемых режимом рисования.
Давайте теперь познакомимся с режимами отображения, поддерживаемыми Windows. Всего их восемь, и основная функция, которая позволяет выбрать режим, а значит, и систему координат — SetMapMode.
virtual int CDC::SetMapMode (int nMapMode)
Эта функция устанавливает направления осей и определяет логические единицы, т. е. единицы измерения для задаваемой системы координат. Возможные режимы задаются параметром nMapMode, который принимает следующие значения:
ММ_ТЕХТ
Одна логическая единица равна одному пикселу, ось х направлена вправо, ось у — вниз; режим задан по умолчанию
MM_HIENGLISH
Одна логическая единица равна 0.001 дюйма, ось х направлена вправо, ось у— вверх
MM_HIMETRIC
Одна логическая единица равна 0.01 миллиметра, ось х направлена вправо, ось у — вверх
MM_LOENGLISH
Одна логическая единица равна 0.01 дюйма, ось х направлена вправо, ось у— вверх
MM_LOMETRIC
Одна логическая единица равна 0.1 миллиметра, ось х направлена вправо, ось у— вверх MM_TWIPS Одна логическая единица — твипс (twips) — равна 1/20 пункта (point) или 1/1440 дюйма, ось х направлена вправо, ось у— вверх
MM_ANISOTROPIC
Режим позволяет настраивать (с помощью функций SetWindowExt и SetViewportExt) размерность (отдельно для каждой из осей), их направления и начало отсчета
MM_ISOTROPIC
Режим позволяет настраивать (с помощью функций SeWindowExt и SetViewportExt) размерность осей, их направления и начало отсчета, однако единица оси х равна единице оси у, т. е. при необходимости GDI настраивает размерность по осям, обеспечивая соотношение 1:1
Примечание
Режим ММ_ТЕХТ назван так не потому, что он наиболее удобен для вывода текста, а потому, что направление осей, т. е. его система координат, соответствует способу чтения, принятому в европейских языках — слева направо и сверху вниз.
Примечание
Исторически в полиграфии используются такие единицы измерения, как пункты (points) и твипсы (twips), размеры которых составляют (приблизительно) 1/72 и 1/1440 дюйма, соответственно. Для обозначения точки экрана мы используем понятие пиксел (pixel).
Отметим, что только режимы MM_TWIPS, MM_HIENGLISH, MM_ HIMETR1C, MMJLOENGLISH и MM_LOMETRIC обеспечивают приложения, с одной стороны, физически понятными единицами измерения, а с другой — определенной независимостью от устройств вывода.
Для первых шести режимов можно менять только начало координат, соответствующее по умолчанию левому верхнему углу области вывода. Для режимов MM_ANISOTROPIC и MM_ISOTROPIC дополнительно можно настраивать направление осей и масштаб. .
И физическая, и логическая области вывода характеризуются точкой, определяющей начало координат. Для настройки начата координат физической области вывода используются функции:
virtual CPoint CDC::SetViewportOrg (
int x,
int y)
или
virtual CPoint CDC::SetViewportOrg (POINT point)..
В свою очередь, для настройки начала координат логической области вывода используются функции
CPoint CDC::SetWindowOrg )
int x,
int у)
или
СPoint CDC::SetWindowOrg (POINT point).
Все четыре функции в качестве параметров получают новые значения для установки начала координат, а возвращают предыдущие значения. Причем если для физической области вывода указываются координаты, которые в дальнейшем будут являться началом координат, то для логической области вывода указываются логические координаты, которые в дальнейшем будут соответствовать левому верхнему углу логической области вывода.
Из вышесказанного следует, что настраивать начало координатной сетки есть смысл только для одной из областей, т. к. система координат логической области вывода привязана к системе координат физической области. Поясним сказанное на примерах.
После настроек функции OnPaint классов CVenmFrame и CEarthFrame будут работать с координатной сеткой, начало координат которой располагается в середине клиентской области (рис. 9.3).
Рис. 9.3. Более привычная, но все еще перевернутая ' система координат
void CVenusFrame::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
...
}
void CEarthFrame::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect) ;
dc.DPtoLP(rect);
dc.SetWindowOrg(-rect.Width() / 2, -rect.Height() / 2);
...
}
В следующем примере попытка настройки систем координат обеих областей вывода в классе CMarsFrame приводит к несколько неожиданным результатам (рис. 9.4), так что такую последовательность, скорее всего, можно считать ошибочной.
void CMarsFrame::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.SetViewportOrg(rect.Width() / 2, rect.Height () / 2);
// Вызовы следующих двух функций необходимы в случае,
// если текущий режим отличен от ММ_ТЕХТ (см. далее),
// т. к. функция SetWindowOrg работает с логическими
// координатами, а в результате преобразования из-за
// несоответствия направления осей длина и ширина области
// могут быть вычислены неверно
//
dc.DPtoLP(rect);
rect.NormalizeRect();
dc.SetWindowOrg (-rect. Width (,: / 2, -rect. Height () / 2);
...
}
Рис. 9.4. С такой системой координат работать будет совсем непривычно
Кроме начала координат, каждая из областей вывода характеризуется еще, что вполне естественно, размерами (extents), которые используются только для определения коэффициента масштабирования. Коэффициент для каждой из осей находится как отношение соответствующих размеров областей вывода. Однако для большинства режимов отображения коэффициент масштабирования изменить невозможно.
Примечание
Размеры области, куда будет осуществляться вывод, определяются размерами клиентской части окна.
Для настройки размеров физической области вывода используются функции:
virtual CSize CDC::SetViewportExt (
int cx,
int cy)
или
virtual CSize CDC::SetViewportExt (SIZE size).
Для настройки размеров логической области вывода используются функции:
virtual CSize CDC::SetWindowExt (
int cx,
int cy)
или
virtual CSize CDC::SetWindowExt (SIZE size).
Все четыре функции в качестве параметров получают новые значения — размеры по осям. Эти значения используются для преобразования логических координат в физические. Кроме того, настройка размеров для физического окна вывода позволяет управлять направлением осей. Поскольку после выбора одного из режимов ось х направлена слева направо, а ось у — сверху вниз, то для изменения направления, например, оси 'у, размер должен быть задан с отрицательным значением. Все функции возвращают предыдущие значения, причем они могут отличаться от тех, что были фактически заданы соответствующими функциями, т. к. Windows настраивает их значения в зависимости от конкретных возможностей или типа устройства. Ниже приводится код, который помещает начало координат в середину клиентской области окна, ось у направлена вверх, а минимальный из размеров по горизонтали или вертикали равен 200 логическим единицам (рис. 9.5). При этом вывод может осуществляться и по координатам, большим 100 или меньшим —100, соответственно.
Примечание
Режим MM_ISOTROPIC предполагает отношение единиц по обоим направлениям как 1:1. Таким образом, задание одинаковых размеров области вывода в окне, имеющем прямоугольную форму (не квадрат), приводит к тому, что по одной из осей фактически размер области вывода может быть больше заданного. С другой стороны, никто не запрещает вызывать функции рисования вне клиентской области окна — они не окажут влияния на другие окна.
void CSaturnFrame::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(rect);
dc.SetMapMode(MM_ISOTROPIC);
dc.SetWindowExt(100, 100);
dc.SetViewportExt(rect.Width(), -rect.Height());
dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
...
}
Рис. 9.5. Вот теперь мы имеем привычную систему координат
Кроме вышеперечисленных функций для установки начала координат и размеров осей, класс CDC содержит ряд функций для модификации текущих установок.
В описании большинства функций рисования указано, что координаты задаются в логических единицах, величина которых зависит от установленного режима. Однако ряд функций продолжают понимать только физические единицы устройства — пикселы — и для них необходимо осуществлять преобразование координат.
Функции этой группы предназначены для преобразования логических координат в физические и наоборот (LPtoDP и DPtoLP). Кроме того, четыре функции - DPtoHIMETRIC, LPtoHIMETRIC, HIMETRICtoDP и HIMETRICtoLP -используются для преобразования координат при передаче размеров объекта OLE и при их получении.
Итак, параметры заданы, объекты рисования выбраны, режимы установлены — можно рисовать. Давайте рассмотрим, какие возможности предоставляет нам класс CDC для рисования различных графических объектов.
Функции этой группы позволяют рисовать рамки (FrameRgn), закрашивать FillRgn и PaintRgn) и инвертировать цвета регионов (InvertRgri).
Функции этой группы добавляют/исключают области отсечения, которые используются для ограничения области перерисовки (SelectClipRgn, ExcludeClipRect, ExcludeUpdateRgn и IntersectClipRect). Кроме того, некоторые функции группы, например GetClipBox и PtVisible, позволяют определить текущую область отсечения для программного исключения перерисовки части рисунка, что з ряде случаев существенно сокращает время вывода. Для повторного вывода сложного объекта могут потребоваться не только многократные вызовы функций настройки различных параметров и функций собственно вывода, но и длительный процесс вычисления (например, при выводе контуров трехмерных объектов).
Функции этой группы предназначены для рисования прямых (LineTo), гладких (Arc, ArcTo и AngleArc) и ломаных линий (Polyline, PofylineTo, PolyPolyline, PolyBezier, PolyBezierTo и Poly Draw), установленных в момент рисования карандашом. Часть функций меняют при этом текущее положение карандаша (LineTo, ArcTo, PolylineTo и PolyBezierTo), другие — нет. Даже если в результате рисования контур получается замкнутым, закрашивание не осуществляется.
Функции этой группы осуществляют рисование закрашенных простейших объектов, прежде всего прямоугольников (FillRect, FillSolidRect и InvertRect), с возможностью задания различного типов рамок (FrameRect, Draw3dRect и DrawEdge). К группе относятся функции рисования пиктограмм и битовых массивов (DrawIcon и DrawState) и элементов управления — кнопок, меню, заголовков окон и полос прокрутки (DrawFrameControl). Большинство функций используют для рисования текущие карандаш и кисть. Остановимся на функции, вернее, на функциях DrawState немного подробнее.
BOOL CDC::DrawState ( BOOL CDC::DrawState (
CPoint pt, CPoint pt,
CSize size, CSize size,
HBITMAP hBitmap, CBitmap* pBitmap,
UINT nFlags, UINT nFlags,
HBRUSH hBrush = NULL) CBrush* pBrush = NULL)
BOOL CDC::DrawState ( BOOL CDC::DrawState (
CPoint pt, CPoint pt,
CSize size, CSize size,
HICON hlcon, HICON hlcon,
UINT nFlags, UINT nFlags,
HBRUSH hBrush = NULL) CBrush* pBrush = NULL)
BOOL CDC::DrawState ( BOOL CDC::DrawState (
CPoint pt, CPoint pt,
CSize size, CSize size,
LPCTSTR IpszText, LPCTSTR IpszText,
UINT nFlags, UINT nFlags,
BOOL bPr4efixText = TRUE, BOOL bPrefixText = TRUE,
int nTextLen = 0, int nTextLen = 0,
HBRUSH hBrush = NULL) CBrush* pBrush = NULL)
"Управляемый вывод" изображений
BjOL CDC::DrawState ( BOOL CDC::DrawState (
CPoint pt, CPoint pt,
CSize size, CSize size,
DRAWSTATEPROC IpDrawFroc, DRAWSTATEPROC IpDrawProc,
LPARAM IData, LPARAM IData,
UINT nFlags, UINT nFlags,
HBRUSH hBrush = NULL; CBrush* pBrush = NULL)
Общие два первых параметра определяют точку привязки (левый верхний угол прямоугольной области вывода — параметр pt) и размеры области вывода (параметр size).
Параметр nFlags определяет тип изображения и может принимать одно из следующих значений:
DST_BITMAP
Битовый массив; в последних двух версиях функции младшее слово параметра Data содержит дескриптор битового массива
DST_COMPLEX
Пользовательский тип изображения; для вывода изображения используется функция обратного вызова (callback), заданная I параметром IpOutputFunc
DST_ICON
Пиктограмма; в последних двух версиях функции младшее I слово параметра IData содержит дескриптор пиктограммы
DST_PREFIXTEXT
Символьная строка; если текст содержит символ "&", при выводе следующий за ним символ выводится с подчеркиванием, символ "&" не выводится; в последних двух версиях функции параметр IData содержит адрес символьной строки, а параметр wData содержит ее длину (количество символов), если этот параметр равен 0, то для определения длины строки она должна завершаться нулевым символом
DST_TEXT
Символьная строка; в последних двух версиях параметр IData содержит адрес символьной строки, а параметр wData содержит ее длину (количество символов), если этот параметр равен 0, то для определения длины строки она должна завершаться нулевым символом
Из названия функции DrawState не совсем ясно, причем тут состояние state). Параметр nFlags может комбинировать со значением, типа изображения следующие флаги состояния, задающие вид модификации изображения;
DSS_NORMAL
Модификации отсутствуют
DSS_UNION
Объединение части изображения с фоном, т. е. частичное разрушение (dithering) изображения (например, строки выводятся серым цветом)
DSS_DISABLED
"Выдавливание" (embossing) изображения— эффект рельефной каменной плиты
DSS_DEFAULT
Вывод изображения в более отчетливой (контрастной) форме
DSS_MONO
Область вывода заполняется при помощи заданной кисти (параметры hBrush или pBrush)
Примечание
В данном случае состояние DSS_DEFAULT названо так не с точки зрения программирования: по умолчанию используется флаг DSS_NORMAL, значение которого равно нулю и, следовательно, может в явном виде не задаваться.
Для всех состояний, кроме DSS_NORMAL, изображение конвертируется в монохромное перед тем, как к нему применяются эффекты.
Отображение эллипсов и многоугольников
Функции этой группы применяются для рисования сложных фигур, таких как эллипсы (Ellipse), сегменты (Chord), сектора (Pie), многоугольники (Rectangle, RoundRect, Polygon и PolyPolygori) и т. д. Функции используют для рисования текущие карандаш и кисть. Для выделения прямоугольной области можно использовать функцию DrawFocusRect, которая выполняет над содержимым области операцию XOR.
Здесь мне хотелось бы обратить ваше внимание на одну особенность рисования "гладких" линий на примере функции Pie:
BOOL CDC::Pie(
HOC hDC, // дескриптор контекста устройства
int nLeftRect, // х-координата верхнего левого угла
int riTotRect, // у-координата верхнего левого угла
int nR'ightRect, // х-координата нижнего правого угла
int nBottomRect, // у-координата нижнего правого угла
int nXStart, // х-координата начала сектора
int nYStart, // у-координата начала сектора
int nXEnd, // х-координата конца сектора
int nYEnd); // у-координата конца сектора
Для соединения точки (nXStart, nYStart) с центром эллипса система использует воображаемую линию. В точке пересечения этой линии с ограничивающим прямоугольником система Windows начинает рисовать дугу эллипса в направлении против часовой стрелки. Рисование дуги завершается в точке пересечения воображаемой линии, соединяющей точку (nXEnd, nYEnd) с центром эллипса, и ограничивающего прямоугольника (рис. 9.6). Точность рисования при таком подходе, конечно же, невысокая, но при этом требуется значительно меньше вычислений, и функция работает достаточно быстро.
Рис. 9.6. Сектор, нарисованный с помощью функции Pie
Контур представляет собой совокупность прямых и изогнутых линий, которая хранится в системе и используется для создания сложных графических объектов. В то же время контур может применяться для создания регионов, например, для ограничения области отсечения.
Чтобы создать контур, необходимо сообщить системе о том, что все последующие вызовы функций рисования должны быть использованы для этой операции. В начале процесса нужно вызвать функцию CDC::BeginPath, а по завершении создания контура — CDC::EndPath. Между вызовами этих двух функций реальный вывод не осуществляется. Для обвода или закраски контура служат функции CDC::StokePath и CDC::FillPath, а чтобы обвести и одновременно закрасить замкнутый контур, необходимо воспользоваться функцией CDC::StrokeAndFillPath.
Только часть функций рисования может быть использована для создания контура. Вот они:
AngleArc Arc ArcTo
Chord CloseFigure Ellipse
ExtTextOut LineTo MoveTo
Pie PolyBezier PolyBezierTo
PolyDraw Polygon Polyline
PolylineTo PolyPolygon PolyPolyline
Rectangle RoundRect TextOut
К сожалению, не все эти функции влияют на содержимое контура так, как хотелось бы: кроме функций вывода текста, сюда относятся только функции рисования линий, ломаных и кривых Безье. Связано это с тем, что контур хранит только координаты вершин составляющих его линий. Например, дуга при прорисовке контура будет заменена прямой линией. Кривые Безье, по сути, являются совокупностями небольших прямых линий или, иначе, ломаными.
Приведем пример создания и использования контуров для закраски символов текста (рис. 9.7), что может быть чрезвычайно полезно, т. к. существенно упрощает сложные операции, реализованные только в мощных графических редакторах.
void CClipPathFrame::OnPaint()
{
CPaintDC dc(this);
CFont font;
font.CreateFont(80, 30, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH I FF_DONTCARE,
"Arial") ;
// Назначаем текущим ранее подготовленный шрифт
CFont *pFont = dc.SelectObject(Sfont);
// т. к. строка нам понадобится несколько раз,
// создадим объект типа CString, что позволит,
// кроме всего прочего, использовать -версии
// функций с меньшим количеством параметров
CString csText = _T("SelectClipPath");
// Узнаем размеры строки, которая будет
// выведена с использованием текущего шрифта
CSize sz = dc.GetTextExtent(csText);
,/ Сообщаем системе о создании контура
dc.Beginpath () ;
// Строка не будет выведена на экран -
//на основе ее очертания будет создан контур
dc.TextOut(10, 10, csText);
// Завершаем создание контура
dc.EndPath();
//На основе контура создаем и устанавливаем
// область отсечения
dc.SelectClipPath(RGN_XOR);
//Выводим горизонтальные линии с изменяемым
// расстоянием между ними
double delta = 2.0;
for (int i = 0; i < sz.cy; i += (int)delta)
{
dc.MoveTo(10, 10+i);
dc.LineTo(10+sz.cx, 10+i);
delta *= 1.025;
}
// Устанавливаем ранее использованный шрифт
dc.SelectObject(pFont);
// Сообщаем системе о том, что далее областью
// отсечения будет вся клиентская область окна
dc.SelectClipRgn(NULL);
}
В результате выполнения этого кода мы получим строку, заливка символов которой не может быть получена обычными средствами.
Рис. 9.7. Без использования регионов добиться аналогичного результата было бы затруднительно
Немного подробнее опишем функцию CDC::SelectClipPath, использованную в примере.
BOOL CDC: : SelectClipPath (int nMode)
Параметр nMode задает один из пяти режимов создания новой области отсечения на основе текущей области и текущего контура. Ниже перечислены возможные режимы (они также используются и в функции создания новой области отсечения с помощью регионов CDC::SelectClipRgn):
RGN_AND
Новая область отсечения включает пересечение текущей области и текущего контура
RGN_COPY
Новая область отсечения совпадает с текущим контуром
RGN_DIFF
Новая область отсечения состоит из текущей, исключая пересечение с текущим контуром
RGN_OR
Новая область отсечения является объединением текущей области и текущего контура
RGN_XOR
Новая область отсечения является объединением текущей области и текущего контура, исключая область пересечения
Графические возможности Windows были бы существенно ограничены, если бы допускали рисование только геометрических фигур или только отображение и копирование растровых (точечных) изображений. Система Windows и вместе с ней класс CDC предоставляют набор достаточно мощных функций, которые позволяют выводить любые рисунки, дополнительно масштабируя их или осуществляя вращение. (К сожалению, последняя возможность есть только в Windows NT — функция PlgBlt.)
Функции, использующие битовые массивы
Функции этой группы применяются для отображения отдельных точек (GetPixel, SetPixel и SetPixelV) или массивов точек, задаваемых битовыми массивами. Отдельно отметим функции копирования и преобразования битовых массивов, а также функции закрашивания замкнутых областей.
Функция PatBit используется для создания массива точек, который формируется в результате комбинации текущей кисти и содержимого области вывода (текущего заполнения).
BOOL CDC::PatBlt (
int x,
int у,
int nWidth,
int nHeight,
DWORD dwRop)
Параметр dwRop определяет режим комбинирования текущей кисти и содержимого области, задаваемой параметрами х, у, nWidth и nHeight. Возможны следующие режимы:
PATCOPY
Заполнение области при помощи текущей кисти
PATINVERT
Комбинирование текущего заполнения с кистью при помощи оператора XOR
DSTINVERT
Инвертирование текущего заполнения
BLACKNESS
Заданная область закрашивается сплошным черным цветом
WHITENESS
Заданная область закрашивается сплошным белым цветом
PATPAINT
Комбинирование инвертированного битового массива с текущей кистью при помощи оператора OR и комбинирование результата этой операции с текущим заполнением при помощи оператора OR
Не все устройства поддерживают выполнение функции PatBit. Для определения поддержки необходимо проверить результат вызова функции GetDeviceCaps с параметром RASTERCAPS (флаг RC_BITBLT).
Функция BitBlt копирует битовый массив из одного контекста устройства в другой.
BOOL CDC::BitBlt (
int x,
int у,
int nWidth,
int nHeight,
CDC* pSrcDC,
int xSrc,
int ySrc,
DWORD dwRop)
Параметр dwRop определяет растровую операцию, используемую при копировании битового массива из контекста устройства, заданного параметром pSrcDC, в область, задаваемую параметрами х, у, nWidth и nHeight. Параметры xSrc и ySrc задают верхний левый угол области контекста устройства источника, который и определяет копируемый битовый массив. Для операций, не требующих битового массива в качестве источника, параметр pSrcDC должен быть равен NULL.
Возможно использование следующих растровых операций:
BLACKNESS
To же, что и для функции PatBIt
DSTINVERT
То же, что и для функции PatBIt
MERGECOPY
Комбинирование текущего заполнения с текущей кистью при помощи оператора AND
MERGEPAINT
Комбинирование инвертированного битового массива с текущим заполнением при помощи оператора OR
NOTSRCCOPY
Копирование инвертированного битового массива
NOTSRCERASE
Инвертирование результата комбинирования текущего заполнения с битовым массивом при помощи оператора OR
PATCOPY
То же, что и для функции PatBIt
PATINVERT
То же, что и для функции PatBIt
PATPAINT
То же, что и для функции PatBIt
SRCAND
Комбинирование текущего заполнения и битового массива при помощи операции AND
SRCCOPY
Заполнение заданной области битовым массивом
SRCERASE
Комбинирование битового массива и инвертированного текущего заполнения при помощи операции AND
SRCINVERT
Комбинирование битового массива и текущего заполнения при помощи операции XOR
SRCPAINT
Комбинирование битового массива и текущего заполнения при помощи операции OR
WHITENESS
To же, что и для функции PatBIt
Примечание
Данная функция выполняется существенно быстрее для окон, имеющих стили CS_BYTEALIGNWINDOW или CS_BYTEALIGNCLIENT. Для указания этих стилей необходимо зарегистрировать класс окна при помощи глобальной функции MFC ::AfxRegisterWndClass.
Если размеры принимающей области больше битового массива источника, GDI вызывает функцию StretchBlt, т. е. происходит масштабирование.
Не все устройства поддерживают выполнение функции BitBlt. Для определения поддержки необходимо проверить результат вызова функции GetDeviceCaps с параметром RASTERCAPS (флаг RC_BITBLT).
Функция StretchBlt копирует битовый массив одного контекста в другой, изменяя размеры.
BOOL CDC::StretchBlt (
int x,
int у,
int nWidth,
int nHeight,
CDC* pSrcDC,
int xSrc,
int ySrc,
int nSrcWidth,
int nSrcHeight,
DWORD dwRop)
Функция копирует битовый массив из контекста устройства, заданного параметром pSrcDC, в область, задаваемую параметрами х, у, nWidth и nHeight. Параметры xSrc и ySrc определяют верхний левый угол области контекста устройства источника, а параметры nSrcWidth и nSrcHeight— размеры битового массива. Если эти параметры имеют разные знаки, то исходный битовый массив отображается зеркально по оси х. Если параметры nHeight и nSrcHeight имеют разные знаки, то исходный битовый массив отображается зеркально по оси у.
При уменьшении или увеличении образа используется режим преобразования, заданный функцией CDC::StretchBltMode.
Параметр dwRop принимает такие же значения, как и для функции BitBlt, хотя операции, не использующие битовые массивы, для этой функции не имеют смысла — масштабировать будет нечего.
Функция осуществляет масштабирование битового массива в памяти и только потом выполняет копирование (с учетом заданного растрового режима) в контекст устройства.
Не все устройства поддерживают выполнение функции StretchBlt. Для определения поддержки необходимо проверить результат вызова функции GetDeviceCaps с параметром RASTERCAPS (флаг RC_STRETCHBLT).
Следующая функция обеспечивает закрашивание произвольных областей с использованием текущей кисти.
BOOL CDC::ExtFloodFill (
int x,
int у,
COLORREF crColor,
UINT nFillType)
Возвращает TRUE при успешном завершении и FALSE в случае возникновения ошибки. Закрашивание невозможно, если определяющий область закрашивания
пиксел, координаты которого заданы параметрами х и у, имеет цвет, совпадающий с crColor, — при режиме закрашивания FLOODFILLBORDER, имеет цвет, не совпадающий с crColor, — при режиме закрашивания FLOODFILLSURFACE или если пиксел находится вне области отсечения.
Параметр crColor определяет либо цвет границы области, либо цвет самой области, что зависит от значения режима определения области закрашивания, задаваемого параметром nFHIType. Всего возможны два режима определения области закрашивания:
FLOODFILLBORDER
Область закрашивания определяется границей, цвет которой задается параметром crColor, этот режим обеспечивается также вызовом функции CDC:: FloodFill
FLOODFILLSURFACE
Область закрашивания определяется цветом, заданным параметром crColor, этот режим полезен для закрашивания областей, граничащих с областями разных цветов
Примечание
Функция CDC::ExtFloodFill поддерживается только контекстами устройств в памяти и растровыми устройствами.
Эта группа содержит только одну функцию — ScrollDC, которая обеспечивает прокрутку прямоугольных областей как по вертикали, так и по горизонтали.
В этом разделе я рассмотрю возможности вывода текста, получения информации о выбранных шрифтах и т. п. С самими объектами рисования — шрифтами — мы познакомились в предыдущей главе.
Функции предназначены для организации вывода текстовых строк. Группа включает функции, выполняющие все необходимые действия от простейшего вывода и настройки режимов выравнивания до получения ряда характеристик, таких как наименование шрифта (GetTextFace), длина заданной строки в логических единицах устройства вывода (GetTextExtent и GetOutpittTextExtent) и установка режима выравнивания (GetTextAlign, SetTextAlign и SetTextJustification). Из всех функций вывода текста остановимся только на основных и самых мощных.
Функция ExtTextOut позволяет осуществлять вывод текстовой строки в заданную прямоугольную область с использованием текущего шрифта и управляет режимами отображения фона. (Для вывода текста с заданной позиции используются функции TextOut и TabbedTextOut.) Функция представлена двумя версиями.
virtual BOOL CDC::ExtTextOut (
int x,
int y,
UINT nOptions,
LPCRECT IpRect,
LPCTSTR IpszString,
UINT nCount, LPINT IpDxWidths)
и
BOOL CDC::ExtTextOut (
int x,
int y,
UINT nOptions,
LPCRECT IpRect,
const CString & str,
LPINT IpDxWidths)
Основное отличие этих версий состоит в механизме задания строки символов. В первой версии строка задается параметром IpszString, а ее длина — параметром nCount, если последний равен -1, то длина строки вычисляется. Во второй версии строка задается ссылкой на объект класса CString, определяемый параметром sir.
Параметр IpDxWidths указывает на массив чисел, определяющих расстояние между символами; если параметр равен NULL, то величина промежутков задается значением по умолчанию.
Параметры х и у задают координаты (в логических единицах) левого верхнего угла области вывода первого символа строки. Параметр IpRect задает прямоугольную область, в которой должен происходить вывод текста, и может быть равен NULL.
Параметр nOptions может принимать одно, оба или не принимать ни одного из следующих значений:
ETO_CLIPPED
Вывод текста осуществляется только в области, заданной параметром IpRect, а параметры х и у игнорируются
ETO_OPAQUE
Перед выводом текста прямоугольная область, заданная параметром IpRect, либо область, требуемая для вывода текста, заполняется текущим цветом фона
По умолчанию текущая позиция вывода после вызова функции не изменяется, однако, если задан флаг TA_UPDATECP при вызове функции CDC::SetTextAlign, параметры х и у игнорируются, вывод осуществляется с текущей позиции, а по завершении вывода текущая позиция устанавливается либо в конец выведенной строки, либо в соответствии с последним элементом массива (параметр IpDxWidths) в зависимости от того, какое значение больше.
Функция DrawText осуществляет текстовый вывод с различными способами форматирования.
virtual int CDC::DrawText (
LPCTSTR IpszString,
int nCount,
LPRECT IpRect,
UINT nFormat)
и
int CDC::DrawText (
const CString & str,
LPRECT IpRect,
UINT nFormat)
Обе реализации в случае успеха возвращают высоту выведенного текста. Строка, как и в функции ExtTextOut, задается параметрами IpszString совместно с nCount или str. Параметр IpRect указывает на структуру ПЕСТ или объект класса CRect, содержащие координаты (в логических единицах) прямоугольной области, в которую, собственно, и происходит форматный вывод текста. Параметр nFormat определяет способ форматирования заданного текста и может быть комбинацией следующих флагов:
DT_BOTTOM
Устанавливает выравнивание по нижней границе заданной прямоугольной области; должен комбинироваться с DT_SINGLELINE
DT_CALCRECT
Служит для определения ширины и высоты прямоугольной области вывода; для текста в несколько строк используется ширина прямоугольной области, заданной параметром IpRect, и настраивается высота так, чтобы поместить весь текст; для текста в одну строку, напротив, ширина настраивается таким образом, чтобы точно соответствовать ширине выводимого текста; в любом случае функция возвращает высоту области, необходимую для полного вывода текста, однако собственно вывод не осуществляется, не может использоваться совместно с DT_TABSTOP
DT_CENTER
Устанавливает выравнивание по центру (по горизонтали) заданной области
DT_EXPANDTABS
Производит при выводе замену символов табуляции на пробелы; каждая табуляция имеет размер в восемь символов
DT_EXTERNALLEADING
При определении высоты строки учитывается размер между строками; не может использоваться совместно с DT_TABSTOP
DT_LEFT
Устанавливает выравнивание по левому краю заданной прямоугольной области
DT_NOCLIP
Осуществляет вывод без учета ширины задаваемой прямоугольной области; не может использоваться совместно с DT_TABSTOP
DT_NOPREFIX
При выводе амперсанд (&) не интерпретируется как указание подчеркивания следующего за ним символа, а двойной амперсанд (&&) — как указание на вывод только одного; не может использоваться совместно с DT_TABSTOP
DT_RIGHT
Устанавливает выравнивание по правому краю заданной прямоугольной области
DT_SINGLELINE
Указывает на вывод одной строки текста, при этом символы перевода строки и возврата каретки не разбивают строку
DT_TABSTOP
Устанавливает размер табуляции, в старшем байте параметра nFormat содержится количество символов на табуляцию (по умолчанию размер табуляции равен восьми символам)
DT_TOP
Устанавливает выравнивание по верхней границе заданной прямоугольной области; должен комбинироваться с DT_SINGLELINE
DT_VCENTER
Устанавливает выравнивание по центру (по вертикали) заданной области; должен комбинироваться с DT.SINGLELINE
DT_WORDBREAK
Устанавливает режим автоматического переноса строки между словами, если следующее слово выходит за рамки заданной прямоугольной области; символы переноса строки интерпретируются как обычно
Функция DrawText для вывода текста использует текущие шрифт, цвет символов и фона. Если флаг DT_NOCLIP не задан, текст не выходит за заданные границы. При этом в случае, если текущий шрифт слишком велик для заданной прямоугольной области, функция DrawText не делает попыток его уменьшить или заменить.
По умолчанию текущая позиция вывода после вызова функции не изменяется, однако, если задан флаг TA_UPDATECP при вызове функции CDC::Se(TextAlign, левый верхний угол области вывода игнорируется — вывод осуществляется с текущей позиции, а по завершении вывода текущая позиция устанавливается в конец выведенного текста. При задании флага TA_UPDATECP флаг DT_WORDBREAK игнорируется.
К этой же группе относятся функции GetOutputTextMetrics и GetTextMetrics, которые поставляют приложению основную информацию о текущем шрифте контекста устройства графического вывода (m_HDС и контекста, используемого для получения параметров вывода (m_hAnribDC), соответственно.
BOOL CDC::GetOutputTextMetrics (LPTEXTMETRIC IpMetrics)
И
BOOL CDC::GetTextMetrics (LPTEXTMETRIC IpMetrics)
Обе функции возвращают TRUE в случае успешного завершения и FALSE в противном случае. В качестве единственного параметра используется указатель на структуру TEXTMETRIC. которая и будет содержать, собственно, запрашиваемую информацию. Важность последней требует подробного описания структуры. Все размеры задаются в логических единицах, т. е. соответствуют текущей системе координат, устанавливаемой функцией SetMapMode.
typedef struct tagTEXTMETRIC (
LONG tmHeight;
LONG tmAscent;
LONG tmDe scent;
LONG tmlnternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tinKaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
BCHAR tmFirstChar;
BCHAR tmLastChar;
BCHAR tmDefaultChar;
BCHAR tmBreakChar;
BYTE tmltaiic;
BYTE tmUnderlined;
BYTE tmStrickOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC;
Остановимся подробнее на элементах структуры, часть которых представлена на рис. 9.8:
tmHeight
Высота символов (tmAscent + tmDescent)
tmAscent
Высота области над базовой линией
tmDescent
Размер области под базовой линией
tmlnternalLeading
Размер дополнительной области над символом, которая может быть использована для знаков ударения или диакритических символов
Рис. 9.8. Определение основных параметров шрифта с помощью элементов структуры TEXTMETRIC
tmExternalLeading
Размер области между строками текста; при выводе эта область никак не заполняется ни в режиме OPAQUE (непрозрачный), ни в режиме TRANSPARENT (прозрачный)
tmAveCharWidth
Средняя ширина символов; обычно определяется шириной для символа "х". Это значение не учитывает ширину символов в режимах bold (полужирный) и italic (курсив)
tmMaxCharWidth
Максимальная ширина символов шрифта
tmWeight
"Вес" или, что еще хуже, "жирность" символов шрифта
tmOverhang
Значение, которое может быть добавлено для определения ширины строки для некоторых синтетических шрифтов (полужирных или курсивных)
ImDigitizedAspectX,
Отношение tmDigitizedAspectX к tmDigitizedAspectY определяет tmDigitizedAspectY масштаб устройства, для которого разрабатывался шрифт
tmFirstChar
Первый определенный в шрифте символ
tmLastChar
Последний определенный в шрифте символ
tmDefaultChar
Символ, используемый для замены неопределенных символов
tmBreakChar
Символ, используемый для разделения слов при выравнивании
tmltalic
Ненулевое значение параметра указывает, что начертание текущего шрифта — курсивное
tmUnderlined
Ненулевое значение параметра указывает, что текст, использующий текущий шрифт, будет подчеркнут
tmStrickOut
Ненулевое значение параметра указывает, что текст, использующий текущий шрифт, будет перечеркнут
tmPitchAndFamily
содержит флаги стиля шрифта.
Старшие четыре бита определяют семейство шрифтов: FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF ROMAN, FF_SCRIPT, FF_SWISS.
Младшие четыре бита определяют тип шрифта:
TMPF_FIXED_PITCH
Пропорциональный шрифт, если бит установлен, и моноширинный (все символы шрифта имеют одинаковую ширину), если сброшен
TMPF_VECTOR
Векторный шрифт
TMPF_TRUETYPE
Если бит установлен, то шрифт является шрифтом TrueType
TMPF_DEVICE
Если бит установлен, то шрифт является шрифтом устройства tmCharSet Определяет таблицу символов шрифта
Примечание
В русском языке тоже есть символы, использующие область InternalLeading, например, "И", который выше "И" как раз на величину tmlnternalLeading.
Функции этой группы служат для получения полной информации о шрифтах (GetFontData, GetKerningPairs, Get OutlineText Metrics, GetGlyphOutline, GetCharABCWidth, GetCharWidih и GetOutputCharWidth), что позволяет выбирать подходящий шрифт и точно определять параметры вывода, такие как размеры, область вывода и т. п.
В этом разделе указаны группы функций, которые непосредственно не занимаются выводом или настройкой, однако связаны с контекстом устройства.
Интерфейс низкого уровня с устройствами
Класс CDC имеет в своем составе функции, которые могут напрямую взаимодействовать не только с принтерами, но и с графическими устройствами (видеокартами). Такие функции (Escape и DrawEscape, соответственно) дают возможность программе выполнять действия, не реализованные средствами GDI. Естественно, наличие таких функций отчасти противоречит идеологии аппаратной независимости, но тем не менее они есть.
Управление процессом печати документов
Функции этой группы предоставляют возможность взаимодействия с системным диспетчером печати (StartDoc, StartPage, EndPage, EndDoc и т. д.).
Функции этой группы предназначены для отображения содержимого метафайла (функция Play'MetaFile) и добавления комментария к метафайлу (функция AddMetaFileComment).