Глава 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). Точность рисования при таком подходе, конечно же, невысокая, но при этом требуется значительно меньше вычислений, и функция работает достаточно быстро.

gl9-6.jpg

Рис. 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);

}

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

gl9-7.jpg

Рис. 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).