- •Подведение итогов
- •Глава 8. Вывод текстовой информации и использование шрифтов
- •Атрибуты шрифтов и диалоговое окно их выбора
- •Задание 1. Генерация программы отображения текста заданным шрифтом и создание ресурсов
- •Задание 2. Реализация обработчика для команды выбора атрибутов шрифта
- •Установка атрибутов текста и его отображение
- •Значения констант выравнивания текста
{ char temp[100]; sprintf(temp, "Paper size: %g\" x %g\".", (double)dlg.m_psd.ptPaperSize.x / 1000.0, // (double)dlg.m_psd.ptPaperSize.y / 1000.0); AfxMessageBox(temp); } }
Параметр формата бумаги по умолчанию измеряется в тысячных долях дюйма.
14. Скомпонуйте, запустите и протестируйте программу. Вы получите окно как на рис. 7.20.
Рис. 7.20. Окончательный вид главного окна программы TabDemo с добавленным меню View
Подведение итогов
В этой главе описаны способы разработки, отображения и управления немодальными диалоговыми окнами, окнами с вкладками (окнами свойств) и стандартными диалоговыми окнами.
Немодальное диалоговое окно можно оставить открытым при работе с главным окном программы. Немодальное диалоговое окно, как и модальное, создается в редакторе диалоговых окон.
Диалоговое окно с вкладками позволяет отображать несколько страниц взаимосвязанных элементов управления в одном диалоговом окне.
Для управления диалоговым окном с вкладками необходимо создать экземпляр класса CPropertySheet (или класса, порождаемого от него). Чтобы управлять каждой отображаемой страницей, необходимо создать объект класса, порождаемого от класса CPropetyPage. Каждый объект страницы связан с созданным в редакторе диалоговых окон шаблоном диалогового окна и добавляется к объекту CPropertySheet при вызове функции CPropertySheet::AddPage().
Чтобы отобразить диалоговое окно с вкладками, следует вызвать функцию CPropertySheet::DoModal().
При использовании стандартных диалоговых окон нет необходимости создавать ресурсы шаблонов диалоговых окон, поскольку они уже определены в соответствующих файлах .dlg.
Все стандартные диалоговые окна являются производными от базового класса CCommonDialog
Особенность стандартных диалоговых окон в том, что они собирают информацию от пользователя, но ничего с ней не делают. Действия по реализации настроек, выполненных в стандартных диалоговых окнах, должна осуществлять программа.
Глава 8. Вывод текстовой информации и использование шрифтов
В этой главе рассматриваются вопросы:
установка и сохранение атрибутов шрифта;
отображение текста выбранным шрифтом;
отображение текста стандартным шрифтом;
поддержка средств прокрутки при отображении текста.
Атрибуты шрифтов и диалоговое окно их выбора
Мы рассмотрим программу TextDemo, демонстрирующую отображение строк текста внутри окна представления, используя для этого разные шрифты, которые можно выбирать в стандатном диалоговом окне Font (рис. 8.1).
Рис. 8.1. Стандартное диалоговое окно Font
Под шрифтом понимают набор печатных символов определенной гарнитуры, размера и начертания (курсивное, полужирное и т.п.). Шрифт включает символы букв и знаков. Размер шрифта измеряется в пунктах. Пункт — это наименьшая единица в типографской системе мер, равная 0,376 мм. 72 пункта составляют один дюйм.
Под гарнитурой шрифта понимают совокупность элементов, определяющих внешний вид его символов. Отличительной особенностью любой гарнитуры является толщина линий и наличие засечек (маленьких линий по нижнему и верхнему краям символа).
Диалоговое окно Font — это одно из стандартных диалоговых окон, предоставляемых Windows. Диалоговое окно Font отображается при создании локального объекта класса CFontDialog и последующем вызове функции CFontDialog::DoModal(). Для создания объекта CFontDialog используют конструктор класса CFontDialog, прототип которого приводится ниже.
CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL );
Конструктор может иметь следующие параметры: lplfInitial— указатель на структуру LOGFONT, хранящую информацию о шрифте; dwFlags — комбинация флагов для инициализации диалогового окна Font; pdcPrinter — указатель на объект контекста принтера; pParentWnd — указатель на родительское окно или окно владельца диалогового окна Font.
Класс CFontDialog инкапсулирует переменную-член m_cf, которая является структурой типа CHOOSEFONT, хранящей характеристики диалогового объекта, и объявлена таким образом:
CHOOSEFONT m_cf;
Перед отображением диалогового окна с помощью функции CFontDialog::DoModal() его можно инициализировать, установив значение полей структуры CFontDialog::m_cf. Структура типа CHOOSEFONT имеет такие поля:
typedef struct tagCHOOSEFONTW { DWORD lStructSize; //длина структуры в байтах HWND hwndOwner; //дескриптор окна-владельца HDC hDC; //дескриптор контекста принтера LPLOGFONT lpLogFont; //указатель на структуру LOGFONT INT iPointSize; //размер выбранного шрифта в //единицах 1/10 пункта DWORD Flags; //флаги инициализации диалогового окна DWORD rgbColors; //цвет шрифта по умолчанию LPARAM lCustData; //зависимые от приложения данные LPCTSTR lpTemplateName; //указатель на имя ресурса //шаблона диалогового окна HINSTANCE hInstance; //дескриптор приложения LPTSTR lpszStyle; //указатель на буфер, содержащий //стиль данных WORD nFontType; //тип выбранного шрифта INT nSizeMin; //минимальный размер шрифта INT nSizeMax; //максимальный размер шрифта } CHOOSEFONT;
Напомним, что функция CFontDialog::DoModal() возвращает значение IDOK, если диалоговое окно закрыть нажатием кнопки OK. Если отменить диалоговое окно, то функция CFontDialog::DoModal() возвратит значение IDCANCEL, что должно привести к выходу из функции, вызывающей CFontDialog::DoModal(). Следующие операторы позволяют создать объект диалогового окна и отобразить его:
CFontDialog FontDialog; if (FontDialog.DoModal () != IDOK) return; //отменить диалоговое окно
После закрытия диалогового окна можно использовать значения полей структуры CFontDialog::m_cf для получения информации о размере, цвете, типе выбранного шрифта. Особый интерес представляет указатель m_cf.lpLogFont на структуру LOGFONT, которую можно использовать для создания логического шрифта. Для этого класс CFontDialog инкапсулирует еще одну переменную-член m_lf, которая является структурой типа LOGFONT:
LOGFONT m_lf;
Все атрибуты шрифта задаются в полях структуры LOGFONT.
typedef struct tagLOGFONT { LONG lfHeight; //высота шрифта LONG lfWidth; //средняя ширина шрифта LONG lfEscapement; //ориентация — угол наклона строки //относительно горизонтальной оси в десятых долях градуса LONG lfOrientation; //наклон символов относительно //горизонтальной оси LONG lfWeight; //толщина шрифта BYTE lfItalic; //курсивное начертание BYTE lfUnderline; //подчеркивание символов BYTE lfStrikeOut; //зачеркивание символов BYTE lfCharSet; //набор символов BYTE lfOutPrecision; //степень соответствия физического //шрифта заданным установкам BYTE lfClipPrecision; //точность отсечения BYTE lfQuality; //качество BYTE lfPitchAndFamily; //межсимвольный интервал и семейство TCHAR lfFaceName[LF_FACESIZE]; //название гарнитуры шрифта } LOGFONT;
Значения многих полей структуры LOGFONT определяются константами. Так, например, в поле m_lf.lfCharSet хранится тип набора символов, задаваемый константами, значения которых приведены ниже:
ANSI_CHARSET BALTIC_CHARSET CHINESEBIG5_CHARSET DEFAULT_CHARSET EASTEUROPE_CHARSET GB2312_CHARSET GREEK_CHARSET HANGUL_CHARSET |
MAC_CHARSET OEM_CHARSET RUSSIAN_CHARSET SHIFTJIS_CHARSET SYMBOL_CHARSET TURKISH_CHARSET VIETNAMESE_CHARSET |
Структура типа LOGFONT используется для инициализации объекта шрифта и хранит описание требуемого шрифта. Если выбрать объект шрифта из объекта контекста устройства, то при отображении текста будет использоваться шрифт, который более всего близок к описанию. Для поля m_lf.lfOutPrecision определены следующие константы (табл. 8.1), которые задают степень соответствия выбранного в диалоговом окне и реально существующего в данной системе шрифтов.
Т а б л и ц а 8.1
Константы соответствия выбранного шрифта и имеющегося в наличии
Значение |
Описание |
OUT_DEFAULT_PRECIS |
Стандартный режим |
OUT_DEVICE_PRECIS |
При наличии нескольких шрифтов с одинаковым названием выбирается аппаратный шрифт. |
OUT_OUTLINE_PRECIS |
Выбирается шрифт TrueType или другой контурный шрифт. |
OUT_RASTER_PRECIS |
Выбирает растровый шрифт при наличии множества шрифтов с тем же названием. |
OUT_TT_ONLY_PRECIS |
Выбираются только TrueType шрифты. Если таких шрифтов нет, то он выбирается по умолчанию. |
OUT_TT_PRECIS |
При наличии нескольких шрифтов с одинаковым названием выбирается контурный (TrueType) шрифт |
В случае выхода символов за пределы области вывода они усекаются. Способ усечения определяется константами, значения которых задаются для поля m_lf.lfClipPrecision и приводятся в табл. 8.2.
Т а б л и ц а 8.2
Константы способа усечения букв при выходе их за границы области вывода
Значение |
Описание |
CLIP_DEFAULT_PRECIS |
Стандартный режим |
CLIP_CHARACTER_PRECIS |
Отсекается весь символ |
CLIP_STROKE_PRECIS |
Отсекается часть символа с точностью до штриха. |
CLIP_EMBEDDED |
Используется внедренный только для чтения шрифт |
CLIP_LH_ANGLES |
Когда используется это значение, угол поворота шрифта зависит от лево- или правосторонней системы координат- |
Качество шрифта при печати определяется константами, значение которых задаются для поля m_lf.lfQuality и приводится в табл. 8.3.
Т а б л и ц а 8.3
Качество шрифта при печати
Значение |
Описание |
DEFAULT_QUALITY |
Вид шрифта не имеет значения |
DRAFT_QUALITY |
Качество вывода играет минимальную роль, допускается масштабирование растровых шрифтов |
PROOF_QUALITY |
Качество вывода важнее, чем соответствие логическим атрибутам шрифта, а масштабирование растровых шрифтов недопустимо — выбирается наиболее близкий по размеру шрифт. |
Шрифты могут иметь фиксированную или переменную ширину литер. В поле m_lf.lfPitchAndFamily в двух младших битах задается межсимвольный интервал, который определяется такими константами: DEFAULT_PITCH — интервал не известен или не имеет значения; FIXED_PITCH — фиксированный интервал; VARIABLE_PITCH — переменный интервал, что характерно для пропорциональных шрифтов. В четырех старших битах поля m_lf.lfPitchAndFamily определяется семейство, к которому относится шрифт. Возможные константы для данного поля приведены в табл. 8.4.
Т а б л и ц а 8.4
Значения констант, определяющих семейство шрифтов
Значение |
Описание |
FF_DECORATIVE |
Декоративный шрифт |
FF_DONTCARE |
Семейство не известно или не имеет значения |
FF_MODERN |
Шрифт с постоянной шириной символа с засечками или без них. |
FF_ROMAN |
Шрифт с засечками с переменной шириной символов |
FF_SCRIPT |
Шрифт, напоминающий рукописный |
FF_SWISS |
Шрифт без засечек с переменной шириной символов |
Для инициализации объекта шрифта необходимо создать объект класса CFont. Для этого используется конструктор CFont(). После создания объекта класса CFont не обходимо инициализировать шрифт с помощью функций CGdiObject::DeleteObject() и CFont::CreateFontIndirect(). Прототипы функций такие:
BOOL CGdiObject::DeleteObject(); BOOL CFont::CreateFontIndirect(const LOGFONT* lpLogFont );
указатель на структуру LOGFONT передается в качестве аргумента в функцию CFont::CreateFontIndirect().
Обращение к функции CGdiObject::DeleteObject() удаляет существующую информацию о шрифте из объекта шрифта. Для этого данный объект предварительно инициализируется предшествующим вызовом функции, обрабатывающей командное сообщение в результате выбора команды меню Font.... Если объект шрифта не был предварительно инициализирован, то вызов функции CGdiObject::DeleteObject() бесполезен, но безопасен. Передача структуры LOGFONT в функцию CFont::CreateFontIndirect() инициализирует (возможно, повторно) объект шрифта описанием вновь выбранного шрифта. После вызова функции CFont::CreateFontIndirect() информация о шрифте хранится внутри объекта шрифта, который можно выбрать в объекте контекста устройства и, как следствие, отобразить текст с использованием соответствующего шрифта.
Инициализировать объект шрифта также можно с помощью функции CFont::CreateFont(), имеющей такой прототип:
BOOL CFont::CreateFont( int nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename );
В список параметров этой функции входят поля структуры LOGFONT.
Каждый раз после инициализации объекта шрифта вызовом функции CFont::CreateFontIndirect() или CFont::CreateFont() можно получить текущую информацию о шрифте, записанную в соответствующем объекте шрифта. Для этого следует вызвать функцию CGdiObject::GetObject(), копирующую эту информацию в структуру LOGFONT. Прототип функции такой:
int CGdiObject::GetObject( int nCount, LPVOID lpObject ) const;
Функция имеет такие параметры: nCount — количество копируемых байтов; lpObject — указатель на буфер, получающий информацию. В качестве буфера используются структуры LOGFONT, LOGBRUSH, LOGPEN и др.
Среди методов класса CFontDialog существуют методы, с помощью которых можно получить имя, размер, цвет, толщину, начертание и др. атрибуты текущего выбранного шрифта. Далее приводятся некоторые методы класса CFontDialog.
Функция CFontDialog::GetCurrentFont() заполняет структуру LOGFONT и позволяет получить все атрибуты выбранного шрифта. Прототип функции такой:
void CFontDialog::GetCurrentFont( LPLOGFONT lplf );
Функция CFontDialog::GetFaceName() возвращает имя выбранного шрифта и имеет такой прототип:
CString CFontDialog::GetFaceName() const;
Функция CFontDialog::GetSize() возвращает размер шрифта. Напомним, что размер шрифта определяется как десятая часть пункта. Прототип функции:
int CFontDialog::GetSize() const;
Функция CFontDialog::GetColor() возвращает цвет шрифта в виде RGB палитры
COLORREF CFontDialog::GetColor() const;
Для определения толщины шрифта используется функция CFontDialog::GetWeight(), для которой существует прототип:
int CFontDialog::GetWeight() const;
Некоторые функции устанавливают факт наличия определенного начертания и эффектов, например, функция CFontDialog::IsBold() проверяет, выбрано ли начертание полужирное или нет.
BOOL CFontDialog::IsBold() const;
Для определения высоты и ширины символов используются логические единицы (logical units). Значение логической единицы определяется режимом отображения (mapping mode). Соответствие между режимом отображения и логической единицей представлено в табл. 8.5.
Т а б л и ц а 8.5
Режимы отображения и логические единицы
Режим отображения |
Логические единицы |
MM_TEXT |
1 пиксел |
MM_HIMETRIC |
0,01 мм |
MM_LOENGLISH |
0,01 дюйма |
MM_ISOTROPIC |
Определяется пользователем |
MM_ANISOTROPIC |
Определяется пользователем |
MM_HIENGLISH |
0,001 дюйма |
MM_LOMETRIC |
0,1 мм |
MM_TWIPS |
1/1440 дюйма |
В режиме MM_ISOTROPIC поддерживается коэффициент пропорциональности (aspect ratio) 1:1, и он используется в тех случаях, когда необходимо точно передать форму изображения. В режиме MM_ANISOTROPIC масштабные множители по осям x и y изменяются независимо друг от друга.
Рис.8.2. Характеристики символа, сохраняемые в структуре TEXTMETRIC
Для хранения атрибутов активного шрифта устройства, т.е. такого, который действительно доступен для любого устройства вывода, используется структура TEXTMETRIC. Все размеры хранятся в логических единицах, т.е. они зависят от текущего режима отображения в объекте контекста устройства. На рис. 8.2 показаны некоторые поля структуры TEXTMETRIC, содержащие размеры символов.
Теперь рассмотрим объявление полей структуры TEXTMETRIC:
typedef struct tagTEXTMETRIC { LONG tmHeight; //высота символов LONG tmAscent; //подъем символа относительно базовой линии LONG tmDescent; //спуск символа относительно базовой линии LONG tmInternalLeading; //количество лидирующих пробелов //внутри границ, определенных высотой символа LONG tmExternalLeading; //междустрочный интервал LONG tmAveCharWidth; //средняя ширина символа LONG tmMaxCharWidth; //максимальная ширина символа LONG tmWeight; //толщина шрифта LONG tmOverhang; //дополнительная ширина строки LONG tmDigitizedAspectX; //горизонтальное положение //устройства, для которого разработан шрифт LONG tmDigitizedAspectY;//вертикальное положение устройства BCHAR tmFirstChar; //значение первого символа шрифта BCHAR tmLastChar; //значение последнего символа шрифта BCHAR tmDefaultChar; //значение символа подстановки вместо //отсутствующего в шрифте BCHAR tmBreakChar; //значение символа для определения конца //слова для выравнивания текста BYTE tmItalic; //курсивный шрифт BYTE tmUnderlined; //подчеркнутый шрифт BYTE tmStruckOut; //зачеркнутый шрифт BYTE tmPitchAndFamily; //межсимвольный интервал и семейство BYTE tmCharSet; //номер набора символов } TEXTMETRIC;
Получить информацию, хранящуюся в структуре TEXTMETRIC, можно с помощью функции CDC::GetTextMetrics(), параметром которой является указатель на структуру TEXTMETRIC. Функция предоставляет полное описание используемого шрифта, применяемого при отображении текста. Прототип функции следующий:
BOOL CDC::GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;
Для отображения текста необходим объект контекста устройства. При создании объекта контекста устройства, связанного с окном представления, используется конструктор класса CClientDC. Параметром конструктора является указатель на объект CWnd класса окна, к клиентской области которого обращается объект контекста устройства.
CClientDC( CWnd* pWnd );
Получение доступа к объекту представления, связанного с объектом документа, обеспечивают функции GetFirstViewPosition() и GetNextView() класса CDocument. Документ может иметь более одного ассоциированного с ним представления, которые организованы в коллекции объектов. Функцию GetFirstViewPosition() класса CDocument вызывают для получения индекса объекта представления этой коллекции. Полученный индекс объекта представления передается в качестве аргумента в функцию CDocument::GetNextView(). Функция CDocument::GetNextView() возвращает указатель на объект представления и устанавливает значение аргумента, равное индексу следующего объекта представления в списке объектов или нулю, если другие представления отсутствуют. Таким образом, эти две функции позволяют обращаться ко всем ассоциированным с документом представлениям. Их прототипы:
virtual POSITION CDocument::GetFirstViewPosition(); virtual CView* CDocument::GetNextView( POSITION& rPosition );
Шрифт можно использовать после его выбора в созданном объекте контекста устройства. Для выбора объекта используют функцию CDC::SelectObject(), параметром которой является указатель на объект шрифта. Прототип функции приводится ниже.
virtual CFont* CDC::SelectObject( CFont* pFont );
Если выбирать объект шрифта из объекта контекста устройства, то при отображении текста будет использоваться шрифт, который более всего близок к описанию. Значения, присваиваемые функцией CDC::GetTextMetrics()полям структуры TEXTMETRIC, задают шрифт, используемый для отображения текста, который фактически доступен в данной системе.
После выбора атрибутов шрифта в диалоговом окне и изменения объекта документа необходимо обновить все объекты представлений. Напомним, что обновление объектов представлений осуществляется в результате такой последовательности вызовов функций: CDocument::UpdateAllViews(), CView::OnUpdate() (вызывается по умолчанию), CTextDemoView::OnDraw(). Напомним прототипы этих функций.
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL );
virtual void CView::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint );
virtual void CView::OnDraw( CDC* pDC ) = 0;
Параметры этих функций имеют следующий смысл: pSender определяет указатель на объект представления, который изменяет документ; lHint содержит информацию об изменениях документа и pHint является указателем на объект, сохраняющий изменения. Если в качестве аргумента в функцию CDocument::UpdateAllViews() передать значение NULL, то все представления будут обновлены. Параметр pDC функции CView::OnDraw() определяет указатель на объект контекста устройства.
Рассмотренные выше функции будут использованы при выполнении заданий, с помощью которых реализуется сохранение выбранных в диалоговом окне Font атрибутов шрифта с целью их дальгнейшего использования при выводе текста в окне представления.