On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru


Крафт пакет для стерилизации с индикатором Винар. Винар крафт пакеты infodez.ru. ; Эро массаж москва эротический массаж в москве.





 

5. Шрифты

5.1. Классификация шрифтов

5.2. Выбор шрифта в контекст отображения

5.3. Приложение FONTVIEW

5.4. Получение информации о шрифте

Не секрет, что своей популярностью операционная система Windows версии 3.1 во многом обязана использованной в ней технологии масштабируемых шрифтов True Type. Только с помощью этих шрифтов можно готовить документы на профессиональном уровне, выполнять верстку изданий и другую аналогичную работу.

Мы уже классификацировали шрифты Windows, поэтому вы знаете, что для приложений доступны растровые, векторные и масштабируемые шрифты (рис. 1.5 в первой главе). Кроме этого, приложения могут использовать шрифты, встроенные или загружаемые в устройство вывода, например, в принтер.

Растровые шрифты удобны для вывода текста на экран (особенно при малой высоте букв), однако для каждого видеорежима и типа контроллера используется свой набор растровых шрифтов.

Векторные шрифты используются в тех случаях, когда в качестве устройства вывода применяется плоттер. Более того, для вывода на плоттер можно использовать только векторные шрифты.

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

Масштабируемые шрифты True Type , доступные приложениям Windows, не только сохраняют свое начертание при произвольном изменении высоты букв, но и обладают другими достоинствами.

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

Еще одно преимущество масштабируемых шрифтов True Type связано с тем, что вы можете встроить такой шрифт непосредственно в документ. Зачем это может понадобиться?

Дело в том, что стандартный набор шрифтов True Type, поставляемых в составе Windows, не всегда удовлетворяет пользователей. Поэтому они приобретают дополнительные шрифты у независимых разработчиков. Однако использование нестандартных шрифтов может привести к проблемам при необходимости переноса документа из одного компьютера в другие, так как там нужного шрифта может не оказаться. Вы, конечно, можете просто скопировать нужный шрифт и перенести его вместе с документом, однако такая процедура может быть запрещена по условию лицензионного соглашения с разработчиками шрифта.

Проблему переноса документа на другой компьютер с сохранением прав разработчиков шрифта можно решить, используя шрифты, встроенные в документ. Пользователь может, например, подготовить документ в текстовом процессоре Microsoft Word for Windows версии 6.0 и встроить в него все использованные шрифты. При переносе такого документа на другой компьютер эти шрифты можно будет использовать для просмотра и, возможно, редактирования этого (и только этого) документа. Возможность редактирования с использованием встроенного шрифта определяется разработчиком шрифта.

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

5.1. Классификация шрифтов

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

Можно сказать, что шрифт состоит из изображений (рисунков) отдельных символов - глифов (glyph).

Для внутреннего представления глифа в файле шрифта True Type используются описания контуров, причем один глиф может содержать несколько контуров (рис. 5.1).

5.1. Рисунки символов

Глифы могут иметь различный внешний вид (typeface). Операционная система Windows классифицирует шрифты на несколько типов, или семейств (font family). Эти типы называются Modern, Roman, Swiss, Script, Decorative.

Шрифты семейства Modern имеют одинаковую ширину букв. Таким шрифтом оформлены все листинги программ в нашей книге. Шрифты семейства Roman содержат буквы различной ширины, имеющие засечки. Семейство Swiss отличается тем, что при переменной ширине букв они не имеют засечек. Буквы в шрифтах семейства Script как бы написаны от руки. Семейство Decorative содержит глифы в виде небольших картинок (пиктограмм).

В следующей таблице мы привели примеры шрифтов различных семейств.

СемействоНазвание шрифта Пример текста
Modern CourierШрифт в стиле Modern
Roman TimesШрифт в стиле Roman
Swiss HelveticaШрифт в стиле Swiss
Script Script Cyrillic Шрифт в стиле Script
Decorative Wingdings Dm13m,0=;rative

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

Другая важная характеристика шрифта - это размер букв. Из 11 тома "Библиотеки системного программиста" вы знаете, что для описания вертикального размера букв шрифта используются несколько параметров. Не останавливаясь на тонкостях, отметим, что шрифты, содержащие буквы разного размера, являются разными шрифтами.

Растровые шрифты, которые относятся к одному семейству, но имеют разные размеры букв, хранятся в отдельных файлах. В то же время благодаря возможности масштабирования шрифтов True Type для них нет необходимости в отдельном хранении глифов различных размеров.

GDI может выполнять масштабирование растровых шрифтов, увеличивая (но не уменьшая) размер букв. Результат такого масштабирования при большом размере букв обычно неудовлетворительный, так как на наклонных линиях контура букв образуются зазубрины (рис. 1.5 в первой главе).

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

Вы знаете, что шрифты могут иметь нормальное (normal), жирное (bold) или наклонное (italic) начертание:

НачертаниеОбразец шрифта
NormalAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНн
BoldAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНн
ItalicAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНнОоПпРр

GDI получает жирное и наклонное начертание растровых шрифтов из нормального при помощи соответствующих алгоритмов утолщения и наклона шрифта. Такие алгоритмы могут быть использованы и для масштабируемых шрифтов True Type, однако лучших результатов можно достигнуть при использовании отдельных файлов шрифтов True Type для нормального, жирного и наклонного начертания.

Еще один часто используемый атрибут оформления строк текста - подчеркивание:

Текст с подчеркиванием

Иногда используется шрифт с перечеркнутыми буквами.

GDI выполняет подчеркивание самостоятельно, файлы шрифтов не содержат глифы с подчеркиванием.

Растровые и векторные шрифты хранятся в системном каталоге Windows в файлах с расширением имени fon.

Глифы масштабируемых шрифтов True Type находятся в файлах с расширением имени ttf, причем сами эти файлы могут располагаться в любом каталоге. В процессе регистрации масштабируемого шрифта Windows создает в своем системном каталоге файлы с расширением имени fot, которые содержат ссылки на соответствующие ttf-файлы.

С помощью приложения Control Panel вы можете добавлять или удалять любые шрифты. Следует, однако, учитывать ограничение: в системе можно одновременно использовать не более 253, к тому же для представления жирного и наклонного начертания используются отдельные масштабируемые шрифты. Чрезмерное количество установленных шрифтов может привести к снижению производительности системы.

5.2. Выбор шрифта в контекст отображения

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

Приложения Windows могут использовать либо один из встроенных шрифтов, либо создать свой, описав требуемые характеристики шрифта. В любом случае в распоряжение пользователя будет предоставлен один из шрифтов, зарегистрированных при установке Windows или позже (с помощью Control Panel). Для выбора шрифта, соответствующего описанию, используется достаточно сложный алгоритм, учитывающий степень важности обеспечения соответствия параметров предоставленного шрифта запрошенным параметрам.

Обратим ваше внимание на одно важное обстоятельство.

Приложение заказывает шрифт, описывая его параметры. GDI анализирует запрошенные параметры и подбирает наиболее подходящий шрифт. При этом приложение не может "заставить" GDI выделить ему какой-то конкретный шрифт, указав его название или путь к файлу. Однако приложение может определить параметры шрифта, выбранного пользователем из состава установленных шрифтов, и запросить у GDI шрифт с этими параметрами. В последнем случае будет выделен шрифт, выбранный пользователем.

Выбор встроенного шрифта

По умолчанию в контекст отображения при его создании выбирается системный шрифт, основным (и почти единственным) преимуществом которого является то, что он всегда доступен. Системный шрифт не является масштабируемым, содержит буквы переменной ширины, не имеющие засечек, для него используется кодировка ANSI.

Однако в некоторых случаях вам может понадобиться шрифт с фиксированной шириной букв, или шрифт в кодировке OEM. Вы можете получить идентификатор одного из встроенных шрифтов при помощи макрокоманды GetStockFont , описанной в файле windowsx.h:

#define GetStockFont(i) ((HFONT)GetStockObject(i))

В качестве единственного параметра этой макрокоманде следует передать идентификатор одного из встроенных шрифтов:

ИдентификаторОписание
SYSTEM_FONT Системный шрифт в кодировке ANSI с переменной шириной букв, используется операционной системой Windows для отображения текста в меню, заголовках окон и диалоговых панелях
SYSTEM_FIXED_FONT Шрифт в кодировке ANSI с фиксированной шириной букв. Использовался в старых версиях операционной системой Windows (до версии 3.0) как системный шрифт
ANSI_VAR_FONT Шрифт в кодировке ANSI с переменной шириной букв
ANSI_FIXED_FONT Шрифт в кодировке ANSI с фиксированной шириной букв
OEM_FIXED_FONT Шрифт в кодировке OEM с фиксированной шириной букв
DEVICE_DEFAULT_FONT Шрифт, который используется для данного устройства по умолчанию. Если устройство не имеет своих шрифтов, используется системный шрифт SYSTEM_FONT

После того как вы получили идентификатор шрифта, этот шрифт можно выбрать в контекст отображения макрокомандой SelectFont :

#define SelectFont(hdc, hfont) \
  ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))

Первый параметр этой макрокоманды определяет идентификатор контекста отображения, в который выбирается шрифт с идентификатором hfont. Она возвращает идентификатор шрифта, который был выбран в контекст отображения раньше, до вызова SelectFont.

Вам не нужно удалять встроенные шрифты, так же как не нужно удалять встроенные кисти и перья.

Определение логического шрифта

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

Приложение может получить идентификатор шрифта, указав его параметры (такие как размеры символов, семейство шрифта, наклон относительно горизонтальной оси и т. п.) функции CreateFont . Эта функция имеет 14 параметров, поэтому не слишком удобна в использовании. Вместо нее лучше пользоваться функцией CreateFontIndirect :

HFONT WINAPI CreateFontIndirect(const LOGFONT FAR* lplf);

Функция возвращает идентификатор созданного логического шрифта, который можно выбрать в контекст отображения макрокомандой SelectFont, при этом для вывода будет подобран наиболее подходящий физический шрифт.

В качестве параметра функции CreateFontIndirect передается указатель на структуру типа LOGFONT , определенную в файле windows.h:

typedef struct tagLOGFONT
{
  int  lfHeight;
  int  lfWidth;
  int  lfEscapement;
  int  lfOrientation;
  int  lfWeight;
  BYTE lfItalic;
  BYTE lfUnderline;
  BYTE lfStrikeOut;
  BYTE lfCharSet;
  BYTE lfOutPrecision;
  BYTE lfClipPrecision;
  BYTE lfQuality;
  BYTE lfPitchAndFamily;
  char lfFaceName[LF_FACESIZE];
} LOGFONT;
typedef LOGFONT*       PLOGFONT;
typedef LOGFONT NEAR* NPLOGFONT;
typedef LOGFONT FAR*  LPLOGFONT;

Перед вызовом функции CreateFontIndirect вы должны заполнить структуру LOGFONT нужными значениями, определяющими параметры шрифта. В неиспользованные поля следует записать нулевые значения. Можно записать нулевые значения во все поля, однако это едва ли имеет смысл.

Опишем назначение отдельных полей структуры LOGFONT. При этом мы будем пользоваться метриками шрифта, описанными в 11 томе "Библиотеки системного программиста" (стр. 144).

lfHeight

Высота шрифта в логических единицах (зависят от установленного режима отображения).

Можно указывать положительные и отрицательные значения, а также нуль. Если указано нулевое значение, выбирается шрифт размером в 12 пунктов (значение по умолчанию).

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

Абсолютная величина отрицательного значения определяет высоту символов, т. е. tmHeight - tmInternalLeading.

lfWidth

Ширина символов в логических единицах.

Если указано нулевое значение, используется значение по умолчанию, которое зависит от высоты шрифта и отношения масштабов по осям координат (aspect ratio) для шрифта и устройства вывода.

lfEscapement

Угол между базовой линией шрифта и координатной осью X в десятых долях градуса (угол отсчитывается в направлении против часовой стрелки).

Если в процессе отображения логического шрифта на физический будет выбран растровый или векторный шрифт, текст будет выведен в горизонтальном направлении, так как вращать можно только шрифты True Type и векторные шрифты.

lfOrientation

Это поле определяет ориентацию символов шрифта. К сожалению, операционная система Windows версии 3.1 игнорирует поле lfOrientation.

lfWeight

Вес шрифта. Определяет жирность символов шрифта и может находиться в пределах от 0 до 1000. Файл windows.h содержит определение символических констант для этого поля:

КонстантаЗначение
FW_DONTCARE 0
FW_THIN 100
FW_EXTRALIGHT 200
FW_ULTRALIGHT 200
FW_LIGHT 300
FW_NORMAL 400
FW_REGULAR 400
FW_MEDIUM 500
FW_SEMIBOLD 600
FW_DEMIBOLD 600
FW_BOLD 700
FW_EXTRABOLD 800
FW_ULTRABOLD 800
FW_BLACK 900
FW_HEAVY 900

Вы можете использовать любое из указанных значений, однако следует иметь в виду, что многие шрифты содержат описания символов только для веса FW_NORMAL, FW_REGULAR и FW_BOLD.

lfItalic

Если содержимое этого поля не равно нулю, запрашивается шрифт с наклонными буквами.

lfUnderline

Если содержимое этого поля не равно нулю, запрашивается шрифт с подчеркиванием букв.

lfStrikeOut

Если содержимое этого поля не равно нулю, запрашивается шрифт с перечеркнутыми буквами.

lfCharSet

Набор символов.

Можно использовать одну из следующих констант, определенных в файле windows.h:

КонстантаЗначениеОписание
ANSI_CHARSET 0 Набор символов в кодировке ANSI
DEFAULT_CHARSET 1 Не используется при отображении шрифтов. Определяется при необходимости запросить шрифт с заданным именем и размером шрифта. Следует использовать с осторожностью, так как если указанного шрифта нет, GDI может выделить шрифт с любым набором символов
SYMBOL_CHARSET 2 Символьный шрифт, такой как, например, Wingdings
SHIFTJIS_CHARSET 128 Шрифт, в котором для представления символов используется двухбайтовая кодировка. Нужен для работы с японской версией Windows
OEM_CHARSET 255 Набор символов в кодировке OEM

lfOutPrecision

Требуемая степень соответствия параметров шрифта.

Это поле используется для того, чтобы указать GDI способ выбора между двумя шрифтами, имеющими одинаковое название, но разный тип. Например, для удовлетворения запроса можно использовать растровый или масштабируемый шрифт с названием OddType. Если в поле lfOutPrecision указать константу OUT_TT_PRECIS, будет выбран масштабируемый шрифт.

Можно указывать одну из следующих констант:

КонстантаЗначениеОписание
OUT_DEFAULT_PRECIS 0 Используется точность, заданная по умолчанию
OUT_STRING_PRECIS 1 Выбирается шрифт, для которого соблюдается наибольшее соответствие в размерах символов
OUT_CHARACTER_PRECIS 2 Аналогично OUT_STRING_PRECIS
OUT_STROKE_PRECIS 3 Требуется точное соответствие между запрошенными атрибутами и атрибутами полученного шрифта
OUT_TT_PRECIS 4Выбирается масштабируемый шрифт True Type, даже если есть подходящий растровый или векторный шрифт
OUT_DEVICE_PRECIS 5 Выбирается шрифт устройства вывода
OUT_RASTER_PRECIS 6 Выбирается растровый шрифт
OUT_TT_ONLY_PRECIS 7 Используются только шрифты True Type

lfClipPrecision

Поле используется для определения способа, при помощи которого обрезается изображение символа, частично попавшего за пределы области ограничения вывода (clipping region), выбранную в контекст отображения.

Можно использовать следующие константы: CLIP_DEFAULT_PRECIS , CLIP_CHARACTER_PRECIS , CLIP_STROKE_PRECIS , CLIP_MASK , CLIP_LH_ANGLES , CLIP_TT_ALWAYS , CLIP_EMBEDDED .

Если указана константа CLIP_LH_ANGLES , направление вращения текста зависит от установленного режима отображения.

lfQuality

Качество шрифта, полученного при отображении.

Можно указывать одну из следующих констант:

КонстантаОписание
DEFAULT_QUALITY Качество не имеет значения
DRAFT_QUALITY Низкое качество. Допустимо масштабирование шрифтов, синтезирование наклонных, жирных, перечеркнутых и подчеркнутых символов
PROOF_QUALITY Высокое качество. Масштабирование шрифтов не допускается. При этом могут быть получены символы, имеющие размер, немного меньший запрошенного

lfPitchAndFamily

С помощью этого поля можно определить, нужна ли фиксированная или переменна ширина символов. Кроме этого, можно определить семейство, к которому должен принадлежать полученный шрифт.

Фиксированная или переменная ширина символов задается при помощи следующих констант:

КонстантаОписание
DEFAULT_PITCH Не имеет значения, будет ли шрифт иметь фиксированную или переменную ширину символов
FIXED_PITCH Нужен шрифт с фиксированной шириной символов
VARIABLE_PITCH Нужен шрифт с переменной шириной символов

Вы можете объединить при помощи логической операции ИЛИ эти константы с константами, соответствующими семейству шрифта:

КонстантаОписание
FF_DECORATIVE Шрифт, содержащий маленькие рисунки (пиктограммы). Примером такого шрифта может послужить шрифт Wingdings, поставляемый в составе Windows
FF_DONTCARE Семейство шрифта не имеет значения
FF_MODERN Семейство Modern. Фиксированная ширина символов, могут быть засечки (но могут и не быть)
FF_ROMAN Семейство Roman. Переменная ширина букв, есть засечки
FF_SCRIPT Семейство Script. Рукописный шрифт
FF_SWISS Семейство Swiss. Переменная ширина букв, нет засечек

lfFaceName

Строка, закрытая двоичным нулем, которая служит названием внешнего вида шрифта. Размер строки (включая закрывающий строку нуль) не должен превышать LF_FACESIZE байт.

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

Выбор созданного шрифта в контекст отображения

Если вы заполнили все нужные поля в структуре LOGFONT и затем передали адрес структуры функции CreateFontIndirect, эта функция вернет идентификатор шрифта. Вы должны выбрать шрифт с этим идентификатором в контекст отображения с помощью макрокоманды SelectFont (точно так же, как для встроенных шрифтов):

hfontOldFont = SelectFont(hdc, hfont);

Как только в созданном шрифте отпадет необходимость, его следует удалить при помощи макрокоманды DeleteFont , предварительно выбрав в контекст отображения тот шрифт, который был выбран в него раньше:

#define DeleteFont(hfont) \
   DeleteObject((HGDIOBJ)(HFONT)(hfont))

Процесс отображения логического шрифта достаточно сложен. GDI сравнивает заданные в структуре LOGFONT параметры с параметрами различных шрифтов, которые можно использовать для данного устройства отображения, выбирая наиболее подходящий шрифт. Для сравнения используются пенальти (штрафные очки), которые имеют разные весовые коэффициенты. Выбирается тот шрифт, для которого сумма пенальти наименьшая.

Наиболее важное поле в структуре LOGFONT - поле lfCharSet. Если в этом поле будет установлено нулевое значение, будет выбран шрифт ANSI_CHARACTER, так как значение соответствующей ему константы равно нулю. Понятно, почему это поле самое важное - если приложение запрашивает шрифт OEM_CHARSET, оно предполагает использовать для вывода кодировку OEM. Если бы GDI предоставил приложению шрифт в кодировке ANSI, скорее всего, строку было бы невозможно прочесть. Если же в Windows нет ни одного шрифта с кодировкой OEM, приложение все равно получит какой-нибудь шрифт, однако результат вывода текста может оказаться неудовлетворительным.

Учтите, что растровые шрифты семейств Modern, Roman и Script, которые пришли из Windows версии 3.0, отмечены как имеющие кодировку OEM, хотя в действительности для этих шрифтов используется кодировка ANSI. Это сделано для того, чтобы в процессе выбора GDI вначале использовал масштабируемые шрифты перечисленных семейств, и только в крайнем случае остановил свой выбор на растровых шрифтах.

Следующее по важности поле в структуре LOGFONT - это поле lfPitchAndFamily. Оно имеет большое значение потому, что приложение, запрашивающее шрифт с фиксированной шириной букв, может работать неправильно, если ему будет выделен шрифт с переменной шириной букв.

Далее следует поле lfFaceName, а после него - поле lfFamily.

После сравнения всех описанных полей GDI сравнивает высоту букв шрифта (поле lfHeight), затем в сравнении принимают участие поля lfWidth, lfItalic, lfUnderline, lfStrikeOut.

Функция ChooseFont

Только что мы приближенно описали алгоритм, который используется GDI для отображения логического шрифта на физический. Нетрудно заметить, что приложение может получить от GDI совсем не тот шрифт, который ему нужен. Поэтому лучше всего предоставить пользователю возможность выбрать шрифт самостоятельно.

DLL-библиотека commdlg.dll содержит функцию ChooseFont , специально предназначенную для выбора одного из зарегистрированных в системе шрифтов. Эта функция выводит на экран диалоговую панель "Font", с помощью которой пользователь может выбрать шрифт, стиль шрифта, размер шрифта, цвет букв, может выбрать подчеркнутый или перечеркнутый шрифт (рис. 5.2).

5.2. Диалоговая панель "Font"

Из списка "Font", который расположен в левой верхней части этой диалоговой панели, пользователь может выбрать название шрифта. Список "Font Style" позволяет выбрать один из доступных стилей, например, наклонный или жирный шрифт. Список "Size" предназначен для выбора размера шрифта. С помощью переключателей "Strikeout" и "Underline", расположенных в поле "Effects", можно создать, соответственно, перечеркнутый и подчеркнутый шрифт. И, наконец, из меню "Color" можно выбрать цвет букв.

Образец выбранного шрифта отображается в поле "Sample".

Обратите внимание на то, что в списке "Font" некоторые шрифты отмечены двойной буквой "T". Это масштабируемые шрифты True Type.

Приведем прототип функции ChooseFont:

BOOL WINAPI ChooseColor(CHOOSEFONT FAR* lpcf);

Единственный параметр функции является указателем на структуру типа CHOOSEFONT. Эта структура, а также сама функция ChooseFont, определены в файле commdlg.h. Структура определена следующим образом:

typedef struct tagCHOOSEFONT
{
  DWORD           lStructSize;
  HWND            hwndOwner;
  HDC             hDC;
  LOGFONT FAR*    lpLogFont;
  int             iPointSize;
  DWORD           Flags;
  COLORREF        rgbColors;
  LPARAM          lCustData;
  UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
  LPCSTR          lpTemplateName;
  HINSTANCE       hInstance;
  LPSTR           lpszStyle;
  UINT            nFontType;
  int             nSizeMin;
  int             nSizeMax;
} CHOOSEFONT;
typedef CHOOSEFONT FAR *LPCHOOSEFONT;

Перед вызовом функции ChooseFont вы должны проинициализировать нужные поля структуры CHOOSEFONT, записав в остальные поля нулевые значения.

Опишем назначение отдельных полей структуры CHOOSEFONT:

ПолеОписание
lStructSizeРазмер структуры в байтах. Это поле необходимо заполнить перед вызовом функции ChooseFont
hwndOwnerИдентификатор окна, которому будет принадлежать диалоговая панель. Если в поле Flags не указан флаг CF_SHOWHELP, в это поле можно записать значение NULL. Поле заполняется до вызова функции ChooseFont
hDCИдентификатор контекста отображения или информационного контекста для принтера. Если установлен флаг CF_PRINTERFONTS, в списке появятся шрифты, доступные в данном контексте
lpLogFontУказатель на структуру LOGFONT. Приложение может заполнить нужные поля в этой структуре перед вызовом функции ChooseFont. Если при этом будет установлен флаг CF_INITTOLOGFONTSTRUCT, выбранные значения будут использоваться в качестве начальных.
iPointSizeРазмер букв выбранного шрифта в десятых долях пункта. Содержимое этого поля устанавливается после возврата из функции ChooseFont
FlagsФлаги инициализации диалоговой панели. Можно использовать следующие значения:CF_APPLY - разрешается использование кнопки "Apply";CF_ANSIONLY - в списке выбора появляются только шрифты в кодировке ANSI;CF_BOTH - в списке шрифтов появляются экранные и принтерные шрифты;CF_TTONLY - можно выбирать только масштабируемые шрифты True Type;CF_EFFECTS - если указан этот флаг, с помощью диалоговой панели можно определять цвет букв создавать подчеркнутые и перечеркнутые шрифты. В этом случае необходимо перед вызовом функции проинициализировать содержимое полей lfStrikeOut, lfUnderline, rgbColors;CF_ENABLEHOOK - разрешается использовать функцию фильтра адрес которой указан в поле lpfnHook;CF_ENABLETEMPLATE - разрешается использование шаблона диалоговой панели, определяемого содержимым полей hInstance и lpTemplateName;CF_ENABLETEMPLATEHANDLE - флаг указывает, что поле hInstance содержит идентификатор загруженного шаблона диалоговой панели. Содержимое поля lpTemplateName игнорируется;CF_FIXEDPITCHONLY - можно выбрать только шрифты с фиксированной шириной символов:CF_FORCEFONTEXIST - выдается сообщение об ошибке, если пользователь пытается выбрать несуществующий шрифт;CF_INITTOLOGFONTSTRUCT - для инициализации диалоговой панели используется содержимое структуры LOGFONT, адрес которой передается через поле lpLogFont;CF_LIMITSIZE - при выборе шрифта учитывается содержимое полей nSizeMin и nSizeMax;CF_NOFACESEL - отменяется выбор в списке "Font";CF_NOOEMFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOVECTORFONTS;CF_NOSIMULATIONS - запрещается эмуляция шрифтов;CF_NOSIZESEL - отменяется выбор размера шрифта;CF_NOSTYLESEL - отменяется выбор стиля шрифта;CF_NOVECTORFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOOEMFONTS;CF_PRINTERFONTS - в списке появляются только такие шрифты, которые поддерживаются принтером, контекст отображения для которого задан в поле hDC;CF_SCALABLEONLY - можно выбирать только масштабируемые и векторные шрифты;CF_SCREENFONTS - можно выбирать только экранные шрифты;CF_SHOWHELP - в диалоговой панели отображается кнопка "Help";CF_USESTYLE - строка lpszStyle содержит указатель на буфер, который содержит строку описания стиля. Эта строка используется для инициализации списка "Font Style" диалоговой панели "Font";CF_WYSIWYG - можно выбирать только такие шрифты, которые доступны и для отображения на экране, и для печати на принтере. Если установлен этот флаг, следует также установить флаги CF_BOTH и CF_SCALABLEONLY
rgbColorsЦвет символов шрифта, который будет выбран в меню "Colors" диалоговой панели "Fonts" сразу после отображения диалоговой панели. Должен использоваться флаг CF_EFFECTS. Поле заполняется до вызова функции ChooseFont, после возврата из функции поле содержит значение выбранного цвета
lCustDataПроизвольные данные, передаваемые функции фильтра, определенной содержимым поля lpfnHook
lpfnHookУказатель на функцию фильтра, обрабатывающую сообщения, поступающие в диалоговую панель. Для работы с фильтром необходимо в поле Flags указать флаг CF_ENABLEHOOK
lpTemplateNameСтрока, закрытая двоичным нулем, которая содержит идентификатор шаблона диалоговой панели. Для использования этого поля необходимо указать флаг CF_ENABLETEMPLATE
hInstanceИдентификатор модуля, который содержит шаблон диалоговой панели в качестве ресурса. Поле используется только в тех случаях, когда в поле Flags указаны значения CF_ENABLETEMPLATE или CF_ENABLETEMPLATEHANDLE. Поле заполняется до вызова функции ChooseFont
lpszStyleУказатель на буфер, содержащий строку, описывающую шрифт. Если указан флаг CF_USESTYLE, эта строка используется для инициализации списка "Font Style". Размер буфера должен быть не меньше LF_FACESIZE байт
nFontTypeТип выбираемого шрифта. Можно использовать одно из следующих значений:SIMULATED_FONTTYPE - GDI может эмулировать этот шрифт;PRINTER_FONTTYPE - принтерный шрифт;SCREEN_FONTTYPE - экранный шрифт;BOLD_FONTTYPE - жирный шрифт, используется только для шрифтов True Type;ITALIC_FONTTYPE - наклонный шрифт, используется только для шрифтов True Type;REGULAR_FONTTYPE - не жирный и не наклонный шрифт, используется только для шрифтов True Type
nSizeMinМинимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE
nSizeMaxМаксимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE

Если пользователь выбрал шрифт, функция ChooseFont возвращает значение TRUE. Если пользователь отказался от выбора, нажав кнопку "Cancel" или клавишу <Esc>, возвращается значение FALSE.

5.3. Приложение FONTVIEW

Для того чтобы вы могли быстро попробовать основные функции, предназначенные для выбора шрифта, мы подготовили приложение FONTVIEW.

Меню "Font" приложения FONTVIEW позволяет вам выбрать шрифт двумя способами - вы можете указать семейство шрифта или выбрать конкретный шрифт при помощи диалоговой панели "Font".

Меню "Orientation" позволяет задать угол поворота текстовой строки, выводя ее с наклоном (рис. 5.3) или даже перевернутой "вверх ногами" (рис. 5.4).

5.3. Вывод текста с наклоном

С помощью этого приложения вы можете убедиться в том, что повернуть можно только масштабируемые шрифты True Type.

5.4. Вывод перевернутого текста

Исходный текст приложения приведен в листинге 5.1.


Листинг 5.1. Файл fontview/fontview.cpp


// ----------------------------------------
// Приложение FONTVIEW
// Просмотр шрифтов
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <mem.h>
#pragma hdrstop

#include "fontview.hpp"

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL GetFont(HWND hWnd, LOGFONT *lf, CHOOSEFONT *cf);

// Имя класса окна
char const szClassName[]   = "FontViewClass";

// Заголовок окна
char const szWindowTitle[] = "Font Viewer";

// Размеры внутренней области окна
short cxClient, cyClient;

// Идентификатор копии приложения
HINSTANCE hInst;

// Строка для вывода
char szChars[] = ": AaBbCcDdEeFfGg АаБбВвГгДдЕе";
char szBuf[256];

// Угол наклона строки при выводе
int nOrientation = 0;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, 
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine, 
        int       nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  hInst = hInstance;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем размеры и расположение
    CW_USEDEFAULT,       // окна, принятые по умолчанию
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    0, 0, hInstance, NULL);      
                       
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна

  // Записываем во все поля структуры нулевые значения
  memset(&wc, 0, sizeof(wc));

  // Подключаем меню 
  wc.lpszMenuName  = "APP_MENU";

  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  static CHOOSEFONT cf;
  static LOGFONT lf;
  static HFONT hfont, hfOldFont;;

  switch (msg)
  {
    // При изменении размеров окна сохраняем
    // новые значения для ширины и высоты
    case WM_SIZE:
    {
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);
      return 0;
    }

    // Рисование в окне
    case WM_PAINT:
    {
      // Получаем контекст отображения для
      // рисования во внутренней области окна 
      hdc = BeginPaint(hwnd, &ps);

      // Устанавливаем угол наклона строки
      lf.lfOrientation = lf.lfEscapement = nOrientation;

      // Создаем шрифт на базе заполненной
      // структуры LOGFONT
      hfont = CreateFontIndirect(&lf);

      if(hfont)
      {
        // Выбираем шрифт в контекст отображения
        hfOldFont = SelectFont(hdc, hfont);

        // Определяем название шрифта
        GetTextFace(hdc, 80, szBuf);

        // Добавляем к нему текстовую строку
        lstrcat(szBuf, szChars);

        // Устанавливаем цвет текста
        SetTextColor(hdc, cf.rgbColors);

        // Выводим текст, пользуясь выбранным шрифтом
        TextOut(hdc, cxClient/2, cyClient/2,
          szBuf, lstrlen(szBuf));

        // Выбираем старый шрифт
        SelectFont(hdc, hfOldFont);

        // Удаляем созданный нами шрифт 
        DeleteFont(hfont);
      }

      // Освобождаем контекст отображения
      EndPaint(hwnd, &ps);
      return 0;
    }

    // Обработка сообщений от меню
    case WM_COMMAND:
    {
      switch (wParam)
      {
        // Выбор шрифта при помощи диалоговой панели
        case CM_FONTSEL:
        {
          // Записываем во все поля структуры типа
          // LOGFONT нулевые значения
          memset(&lf, 0, sizeof(LOGFONT));

          // Выбираем шрифт
          if(GetFont(hwnd, &lf, &cf))
          {
            // Перерисовываем окно
            InvalidateRect(hwnd, NULL, TRUE);
          }
          return 0;
        }

        // Выбираем шрифт, указывая семейство
        case CM_FDECOR:
        {
          memset(&lf, 0, sizeof(LOGFONT));
          lf.lfPitchAndFamily = FF_DECORATIVE;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FMODERN:
        {
          memset(&lf, 0, sizeof(LOGFONT));
          lf.lfPitchAndFamily = FF_MODERN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FROMAN:
        {
          memset(&lf, 0, sizeof(LOGFONT));
          lf.lfPitchAndFamily = FF_ROMAN;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FSCRIPT:
        {
          memset(&lf, 0, sizeof(LOGFONT));
          lf.lfPitchAndFamily = FF_SCRIPT;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FSWISS:
        {
          memset(&lf, 0, sizeof(LOGFONT));
          lf.lfPitchAndFamily = FF_SWISS;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        // Выбираем угол поворота строки
        case CM_FONT00:
        {
          nOrientation = 0;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT30:
        {
          nOrientation = 300;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT45:
        {
          nOrientation = 450;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT90:
        {
          nOrientation = 900;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT180:
        {
          nOrientation = 1800;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT270:
        {
          nOrientation = 2700;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }
        case CM_FONT360:
        {
          nOrientation = 3600;
          InvalidateRect(hwnd, NULL, TRUE);
          return 0;
        }

        case CM_HELPABOUT:
        {
          MessageBox(hwnd,
            "Font Viewer, v.1.0\n"
            "(C) Frolov A.V., 1994",
            "About FONTVIEW", MB_OK | MB_ICONINFORMATION);
          return 0;
        }

        // Завершаем работу приложения
        case CM_FILEEXIT:
        {
          DestroyWindow(hwnd);
          return 0;
        }

        default:
          return 0;
      }
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }

    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция GetFont
// =====================================

BOOL GetFont(HWND hWnd, LOGFONT *lf, CHOOSEFONT *cf)
{
  LPSTR szFontStyle[LF_FACESIZE];

  // Записываем нулевые значения во все поля
  // структуры, которая будет использована для
  // выбора шрифта
  memset(cf, 0, sizeof(CHOOSEFONT));

  // Размер структуры
  cf->lStructSize = sizeof(CHOOSEFONT);

  // Идентификатор окна
  cf->hwndOwner = hWnd;

  // Указатель на структуру LOGFONT 
  cf->lpLogFont = lf;

  // Флаги, определяющие внешний вид диалоговой панели
  cf->Flags = CF_SCREENFONTS | CF_USESTYLE
            | CF_EFFECTS;

  // Дополнительные данные
  cf->lCustData = 0L;

  // Цвет текста
  cf->rgbColors = RGB(0,0,0);

  // Адрес функции фильтра 
  cf->lpfnHook = (FARPROC)NULL;

  // Адрес шаблона диалоговой панели 
  cf->lpTemplateName = (LPSTR)NULL;

  // Идентификатор копии приложения
  cf->hInstance = hInst;

  // Стиль шрифта
  cf->lpszStyle = (LPSTR)szFontStyle;

  // Тип шрифта
  cf->nFontType = SCREEN_FONTTYPE;

  // Ограничения на минимальный и максимальный
  // размер шрифта
  cf->nSizeMin = 0;
  cf->nSizeMax = 0;

  // Вызываем функцию выбора шрифта
  return ChooseFont(cf);
} 

Текстовая строка, которая выводится на экран, находится в глобальном массиве szChars. В переменной nOrientation находится текущее значение угла поворота, которое задается при помощи меню "Orientation".

Обработчик сообщения WM_PAINT пользуется структурой lf типа LOGFONT, подготовленной при выборе шрифта.

Перед созданием шрифта обработчик устанавливает нужный угол наклона строки:

lf.lfOrientation = lf.lfEscapement = nOrientation;

Затем создается шрифт:

hfont = CreateFontIndirect(&lf);

Далее шрифт выбирается в контекст отображения, для чего используется макрокоманда SelectFont:

hfOldFont = SelectFont(hdc, hfont);

Идентификатор шрифта, который был выбран в контекст отображения раньше, сохраняется в переменной hfOldFont.

Затем обработчик вызывает функцию GetTextFace, которая копирует в буфер szBuf текстовую строку с названием шрифта, выбранного в контекст отображения. Эта строка затем дописывается ко строке szChars и выводится на экран.

Перед выводом устанавливается цвет текста, который берется из заполненной на этапе выбора шрифта структуры CHOOSEFONT:

SetTextColor(hdc, cf.rgbColors);

Для вывода текста мы используем функцию TextOut, которая была подробно описана в 11 томе "Библиотеки системного программиста".

Перед возвратом управления обработчик сообщения WM_PAINT выбирает в контекст отображения старый шрифт и удаляет созданный шрифт:

SelectFont(hdc, hfOldFont);
DeleteFont(hfont);

Когда вы выберите строку "Fonts..." из меню "Font", получит управление обработчик сообщения WM_COMMAND. Он запишет во все поля структуры lf типа LOGFONT нулевые значения и вызовет функцию GetFont, определенную в нашем приложении. После этого он вызовет функцию InvalidateRect для перерисовки окна приложения.

Функция GetFont инициализирует нулевыми значениями структуру cf типа CHOOSEFONT, а затем заполняет в этой структуре нужные поля и вызывает функцию ChooseFont:

memset(cf, 0, sizeof(CHOOSEFONT));
cf->lStructSize = sizeof(CHOOSEFONT);
cf->hwndOwner = hWnd;
cf->lpLogFont = lf;
cf->Flags = CF_SCREENFONTS | CF_USESTYLE
          | CF_EFFECTS;
cf->lCustData = 0L;
cf->rgbColors = RGB(0,0,0);
cf->lpfnHook = (FARPROC)NULL;
cf->lpTemplateName = (LPSTR)NULL;
cf->hInstance = hInst;
cf->lpszStyle = (LPSTR)szFontStyle;
cf->nFontType = SCREEN_FONTTYPE;
cf->nSizeMin = 0;
cf->nSizeMax = 0;
return ChooseFont(cf);

Если вы выбираете из меню "Font" одно из семейств шрифтов, структура lf инициализируется нулевыми значениями, а затем в ней устанавливается поле lfPitchAndFamily:

memset(&lf, 0, sizeof(LOGFONT));
lf.lfPitchAndFamily = FF_DECORATIVE;

Затем вызывается функция InvalidateRect, что приводит к перерисовке окна приложения.

Установка угла наклона выполняется достаточно просто и заключается в изменении значения переменной nOrientation с последующей перерисовкой окна:

case CM_FONT30:
{
  nOrientation = 300;
  InvalidateRect(hwnd, NULL, TRUE);
  return 0;
}

Все константы, которые используются для работы с меню, описаны в файле fontview.hpp (листинг 5.2).


Листинг 5.2. Файл fontview/fontview.hpp


#define CM_HELPABOUT       301
#define CM_FONTSEL         302
#define CM_FILEEXIT        303

#define CM_FONT30          304
#define CM_FONT45          305
#define CM_FONT90          306
#define CM_FONT180         307
#define CM_FONT270         308
#define CM_FONT360         309
#define CM_FONT00          310

#define CM_FDECOR          311
#define CM_FMODERN         312
#define CM_FROMAN          313
#define CM_FSCRIPT         314
#define CM_FSWISS          315

Меню определено в файле ресурсов приложения (листинг 5.3).


Листинг 5.3. Файл fontview/fontview.rc


#include "fontview.hpp"

APP_MENU MENU 
BEGIN
  POPUP "&File"
    BEGIN
      MENUITEM "E&xit",          CM_FILEEXIT
    END

  POPUP "F&ont"
    BEGIN
      MENUITEM "FF_DECORATIVE",  CM_FDECOR
      MENUITEM "FF_MODERN",      CM_FMODERN
      MENUITEM "FF_ROMAN",       CM_FROMAN
      MENUITEM "FF_SCRIPT",      CM_FSCRIPT
      MENUITEM "FF_SWISS",       CM_FSWISS
      MENUITEM SEPARATOR
      MENUITEM "&Select Font...",CM_FONTSEL
    END

  POPUP "&Orientation"
    BEGIN
      MENUITEM "0", CM_FONT00
      MENUITEM "30",CM_FONT30
      MENUITEM "45",CM_FONT45
      MENUITEM "90",CM_FONT90
      MENUITEM "180",CM_FONT180
      MENUITEM "270",CM_FONT270
      MENUITEM "360",CM_FONT360
    END

  POPUP "&Help"
    BEGIN
      MENUITEM "&About...",      CM_HELPABOUT
    END
END

Файл определения модуля приложения FONTVIEW приведен в листинге 5.4.


Листинг 5.4. Файл fontview/fontview.def


; =============================
; Файл определения модуля
; =============================
NAME        FONTVIEW
DESCRIPTION 'Приложение FONTVIEW, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   8120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

5.4. Получение информации о шрифте

В программном интерфейсе GDI имеется несколько функций, с помощью которых приложение может получить различную информацию о шрифте, выбранном в контекст отображения. Наибольший интерес представляют метрики шрифта, о которых мы рассказывали в 11 томе "Библиотеки системного программиста", однако для масштабируемых шрифтов True Type можно получить и другую информацию.

Определение метрик шрифта

Для удобства мы напомним вам методику определения метрик шрифта.

Метрику шрифта , выбранного в контекст отображения, можно определить с помощью функции GetTextMetrics :

BOOL WINAPI GetTextMetrics(HDC hdc, TEXTMETRIC FAR* lptm);

Параметр hdc указывает контекст отображения или устройства, для которого требуется получить информацию о метрике шрифта. В качестве этого параметра можно использовать значение, возвращаемое функцией BeginPaint или GetDC.

Параметр lptm является дальним указателем на структуру типа TEXTMETRIC, в которую будет записана информация о метриках шрифта, выбранного в указанный контекст устройства.

В случае успешного завершения функция возвращает значение TRUE, в противном случае - FALSE.

Структура TEXTMETRIC описана в файле windows.h следующим образом:

typedef struct tagTEXTMETRIC
{
  int    tmHeight;
  int    tmAscent;
  int    tmDescent;
  int    tmInternalLeading;
  int    tmExternalLeading;
  int    tmAveCharWidth;
  int    tmMaxCharWidth;
  int    tmWeight;
  BYTE   tmItalic;
  BYTE   tmUnderlined;
  BYTE   tmStruckOut;
  BYTE   tmFirstChar;
  BYTE   tmLastChar;
  BYTE   tmDefaultChar;
  BYTE   tmBreakChar;
  BYTE   tmPitchAndFamily;
  BYTE   tmCharSet;
  int    tmOverhang;
  int    tmDigitizedAspectX;
  int    tmDigitizedAspectY;
} TEXTMETRIC;

Параметры, имеющие отношение к вертикальным размерам букв, представлены на рис. 5.5.

5.5. Метрики шрифта

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

Общая высота букв находится в поле tmHeight структуры TEXTMETRIC. Эта высота складывается из двух компонент - tmAscent и tmDescent. Компонента tmAscent представляет собой высоту букв от базовой линии с учетом таких элементов, как тильда в букве "Й". Компонента tmDescent определяет пространство, занимаемое буквами ниже базовой линии. Сумма tmAscent и tmDescent в точности равна tmHeight.

Величина tmInternalLeading определяет размер выступающих элементов букв и может быть равна нулю.

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

Для ширины букв в структуре TEXTMETRIC есть два поля с именами tmAveCharWidth и tmMaxCharWidth. Поле tmAveCharWidth содержит среднее значение ширины строчных букв шрифта. Это значение приблизительно соответствует ширине латинской буквы "x". Поле tmMaxCharWidth определяет ширину самой широкой буквы в шрифте. Для шрифта с фиксированной шириной букв поля tmAveCharWidth и tmMaxCharWidth содержат одинаковые значения, которые зависят от самого шрифта.

Поле tmWeight определяет жирность шрифта. Может находиться в пределах от 0 до 1000. Файл windows.h содержит определение символических констант для этого поля:

КонстантаЗначение
FW_DONTCARE0
FW_THIN100
FW_EXTRALIGHT200
FW_ULTRALIGHT200
FW_LIGHT300
FW_NORMAL400
FW_REGULAR400
FW_MEDIUM500
FW_SEMIBOLD600
FW_DEMIBOLD600
FW_BOLD700
FW_EXTRABOLD800
FW_ULTRABOLD800
FW_BLACK900
FW_HEAVY900

Поля tmItalic, tmUnderlined, tmStruckOut определяют, соответственно, является ли шрифт наклонным, подчеркнутым или перечеркнутым.

Поля tmFirstChar и tmLastChar определяют, соответственно, коды первого и последнего символа, определенных в шрифте.

Если приложение пытается вывести символ, код которого отсутствует в шрифте, вместо него будет выведен символ с кодом, расположенным в поле tmDefaultChar.

Поле tmBreakChar содержит код символа, который используется для переноса слов с одной строки на другую при выравнивании текста.

Поле tmPitchAndFamily содержит код семейства шрифта. В нем могут находится следующие флаги, соответствующие четырем младшим битам:

ЗначениеОписание
TMPF_FIXED_PITCH Шрифт с фиксированной шириной букв
TMPF_VECTOR Векторный шрифт или масштабируемый шрифт True Type
TMPF_TRUETYPE Шрифт True Type
TMPF_DEVICE Шрифт устройства вывода, например, принтерный шрифт

Одновременно может быть установлено несколько флагов с префиксом имени TMPF.

Старшие четыре бита описывают семейство шрифта:

КонстантаОписание
FF_DECORATIVEШрифт, содержащий маленькие рисунки (пиктограммы). Примером такого шрифта может послужить шрифт Wingdings, поставляемый в составе Windows
FF_DONTCAREСемейство шрифта не имеет значения или неизвестно
FF_MODERNСемейство Modern. Фиксированная ширина символов, могут быть засечки (но могут и не быть)
FF_ROMANСемейство Roman. Переменная ширина букв, есть засечки
FF_SCRIPTСемейство Script. Рукописный шрифт
FF_SWISSСемейство Swiss. Переменная ширина букв, нет засечек

В поле tmCharSet находится код используемого набора символов:

КонстантаЗначениеОписание
ANSI_CHARSET0 Набор символов в кодировке ANSI
DEFAULT_CHARSET1 Не используется при отображении шрифтов. Определяется при необходимости запросить шрифт с заданным именем и размером шрифта. Следует использовать с осторожностью, так как если указанного шрифта нет, GDI может выделить шрифт с любым набором символов
SYMBOL_CHARSET2 Символьный шрифт, такой как Wingdings
SHIFTJIS_CHARSET128 Шрифт, в котором для представления символов используется двухбайтовая кодировка. Нужен для работы с японской версией Windows
OEM_CHARSET255 Набор символов в кодировке OEM

В поле tmOverhang содержится величина, на которую увеличивается ширина символов для синтезированных (эмулированных) шрифтов, например, наклонных или жирных шрифтов, полученных изменением нормального шрифта. Шрифты True Type обычно не используют это поле для наклонных и жирных шрифтов (в нем находится нулевое значение), так как такие шрифты считаются отдельными шрифтами, и не получаются изменением нормального шрифта True Type.

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

Функция EnumFontFamilies

В тех случаях, когда вас не устраивают возможности диалоговой панели "Font", создаваемой функцией ChooseFont, придется использовать для выбора шрифтов список, создаваемый с помощью функции EnumFontFamilies . Эту функцию можно также использовать для получения информации о шрифте.

Приведем прототип функции EnumFontFamilies:

int EnumFontFamilies(
  HDC hdc,           // идентификатор контекста отображения
  LPCSTR lpszFamily, // адрес имени семейства шрифта
  FONTENUMPROC fntenmprc, // адрес функции обратного вызова
  LPARAM lParam);         // произвольные данные

Параметр hdc определяет контекст отображения устройства, для которого требуется получить список доступных шрифтов.

Через параметр lpszFamily передается адрес строки, закрытой двоичным нулем, содержащей название шрифта, для которого требуется получить информацию. Если этот параметр указан как NULL, выбирается один произвольный шрифт для каждого семейства шрифтов.

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

Приложение может передать функции обратного вызова произвольные 32-разрядные данные через параметр lParam.

Функция обратного вызова должна быть определена следующим образом (для функции можно использовать любое имя):

int CALLBACK _export EnumFontFamProc(
  NEWLOGFONT FAR* lpnlf,    // адрес структуры NEWLOGFONT
  NEWTEXTMETRIC FAR* lpntm, // адрес структуры метрики 
                            // физического шрифта
  int FontType,             // тип шрифта
  LPARAM lParam); // адрес произвольных данных, переданных
                  // функции EnumFontFamilies через
                  // параметр lParam 

Когда функция EnumFontFamProc получает управление, через параметр lpnlf передается адрес структуры NEWLOGFONT , которая по непонятной причине не описана в файле windows.h. Эта структура аналогична структуре LOGFONT, но имеет в конце два дополнительных поля, определенных только для шрифтов True Type:

typedef struct tagNEWLOGFONT
{
  int  lfHeight;
  int  lfWidth;
  int  lfEscapement;
  int  lfOrientation;
  int  lfWeight;
  BYTE lfItalic;
  BYTE lfUnderline;
  BYTE lfStrikeOut;
  BYTE lfCharSet;
  BYTE lfOutPrecision;
  BYTE lfClipPrecision;
  BYTE lfQuality;
  BYTE lfPitchAndFamily;
  char lfFaceName[LF_FACESIZE];

BYTE lfFullName[2 * LF_FACESIZE];// только для True Type

  BYTE lfStyle[LF_FACESIZE];       // только для True Type
} NEWLOGFONT;

Поле lfFullName представляет собой массив, содержащий полное имя шрифта, которое состоит из названия шрифта и названия стиля.

В поле lfStyle находится название стиля шрифта.

Параметр lpntm функции EnumFontFamProc содержит адрес структуры NEWTEXTMETRIC , описывающей метрику шрифта:

typedef struct tagNEWTEXTMETRIC
{
   int   tmHeight;
   int   tmAscent;
   int   tmDescent;
   int   tmInternalLeading;
   int   tmExternalLeading;
   int   tmAveCharWidth;
   int   tmMaxCharWidth;
   int   tmWeight;
   BYTE  tmItalic;
   BYTE  tmUnderlined;
   BYTE  tmStruckOut;
   BYTE  tmFirstChar;
   BYTE  tmLastChar;
   BYTE  tmDefaultChar;
   BYTE  tmBreakChar;
   BYTE  tmPitchAndFamily;
   BYTE  tmCharSet;
   int   tmOverhang;
   int   tmDigitizedAspectX;
   int   tmDigitizedAspectY;

   // Дополнительные поля
   DWORD ntmFlags;
   UINT  ntmSizeEM;
   UINT  ntmCellHeight;
   UINT  ntmAvgWidth;
} NEWTEXTMETRIC;
typedef NEWTEXTMETRIC*       PNEWTEXTMETRIC;
typedef NEWTEXTMETRIC NEAR* NPNEWTEXTMETRIC;
typedef NEWTEXTMETRIC FAR*  LPNEWTEXTMETRIC;

Структура NEWTEXTMETRIC аналогична структуре TEXTMETRIC, за исключением четырех дополнительных полей, добавленных в конце. Эти поля описывают физические атрибуты шрифта True Type.

Поле ntmFlags может содержать значения NTM_REGULAR, NTM_BOLD или NTM_ITALIC, соответственно, для нормального, жирного или наклонного шрифта True Type.

Поле ntmSizeEM содержит ширину буквы "М", в единицах, использованных при разработке шрифта.

В поле ntmCellHeight находится высота шрифта в единицах, использованных при разработке шрифта.

Поле ntmAvgWidth содержит ширину шрифта в единицах, использованных при разработке шрифта.

Параметр FontType функции EnumFontFamProc определяет тип шрифта и может содержать одно из следующих значений:

ЗначениеОписание
DEVICE_FONTTYPE Шрифт устройства вывода
RASTER_FONTTYPE Растровый шрифт
TRUETYPE_FONTTYPE Шрифт True Type

Через последний параметр функции EnumFontFamProc передаются 32-разрядные данные, указанные в параметре lParam функции EnumFontFamilies.

Если приложение собирается продолжить просмотр доступных шрифтов, функция EnumFontFamProc должна возвратить ненулевое значение. Если просмотр должен быть завершен, следует возвратить нуль.

Назад       Содержание       Вперёд