Класс CFont. Вывод текста под наклоном

Класс CFont (шрифт) инкапсулирует графический объект Windows шрифт. Для создания объекта этого класса существует конструктор без параметров. Чтобы создать собственный шрифт, можно вызвать одну из следующих функций: CreateFont, CreateFontIndirect, CreatePointFont или CreatePointFontIndirect.

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

...
LOGFONT lf={ ...};
CPaintDC dc(this);
CFont font;
font.CreateFontIndirect(&lf);
CFont *pFont = dc.SelectObject(&font);
...

После использования нужно вернуть ранее установленный шрифт и удалить созданный шрифт:

dc.SelectObject(pFont);
font.DeleteObject();

Можно создать шрифт при помощи функции
BOOL CreateFontIndirect( const LOGFONT* lpLogFont )
Единственный параметр lpLogFont этой функции указывает на структуру LOGFONT, которая и определяет шрифт:

typedef struct tagLOGFONT { /* lf */
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;
CHAR lfFaceName[LF_FACESIZE];
} LOGFONT;

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

  1. Если lfHeight>0, то значение преобразуется в единицы устройства вывода и используется для выбора шрифта из имеющихся, соответствующего по высоте символа
  2. Если lfHeight=0, то для нахождения шрифта используется значение высоты по умолчанию
  3. Если lfHeight<0, то значение преобразуется в единицы устройства вывода и используется для выбора шрифта из имеющихся, соответствующего по высоте символа

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

Для режима отображения ММ_ТЕХТ высота может быть определена через размер шрифта, задаваемого в пунктах (points), следующим образом:
lfHeight=-MulDiv(PointSize, dc.GetDeviceCaps(LOGPIXELSY), 72);

Поле lfWidth определяет определяет среднюю ширину символов в логических единицах. Если lfWidth=0, то выбирается шрифт, наиболее подходящий конкретному устройству (device) по возможностям масштабирования.

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

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

Примечание
В Windows 95/98 значения полей lfEscapement и lfOrientation должны совпадать, т.е. вся строка текста должна иметь один и тот же наклон, при этом когда базовые линии символов лежат на базовой линии строки. В Windows NT при установке графического режима GM_ADVANCED (при помощи Win32 API функции SetGraphicsMode) lfEscapement и lfOrientation не обязательно должны быть равны.

lfWeight определяет толщину шрифта и принимает значения в диапазоне от 0 до 1000. Если lfWeight=0, то используется толщина(weight) по умолчанию.

Weight Value
0 FW_DONTCARE
100 FW_THIN
200 FW_EXTRALIGHT
200 FW_ULTRALIGHT
300 FW_LIGHT
400 FW_NORMAL
400 FW_REGULAR
500 FW_MEDIUM
600 FW_SEMIBOLD
700 FW_DEMIBOLD
700 FW_BOLD
800 FW_EXTRABOLD
800 FW_ULTRABOLD
900 FW_HEAVY
900 FW_BLACK

Поле lfItalic определяет установлено ли курсивное начертание шрифта.

Поле lfUnderline определяет установлено ли подчеркнутое начертание шрифта.

Поле IfStrikeOut определяет установлено ли перечеркнутое начертание шрифта.

Поле lfCharSet определяет кодировку шрифта. Определены следующие кодировки: ANSI_CHARSET, DEFAULT_CHARSET, SYMBOL_CHARSET, SHIFTJIS_CHARSET, GB2312_CHARSET, HANGEUL_CHARSET, CHINESEBIG5_CHARSET, OEM_CHARSET. В Windows 95 также определены: JOHAB_CHARSET, HEBREW_CHARSET, ARABIC_CHARSET, GREEK_CHARSET, TURKISH_CHARSET, THAI_CHARSET, EASTEUROPE_CHARSET, RUSSIAN_CHARSET, MAC_CHARSET, BALTIC_CHARSET.
Значение OEM_CHARSET определяет кодировку, не зависющую от операционной системы.
Значение DEFAULT_CHARSET требует задания имени (поля IfFaceName) и размера шрифта. Отсутствие запрашиваемого шрифта может привести к непредсказуемым результатам, т.к. он будет подменен шрифтом, подходящим по другим параметрам, но неизвестной кодировкой. Особенно важно задание правильной кодировки при указании имени шрифта в явном виде, т.к. именно кодировка в первую очередь определяет набор установленных шрифтов, среди которых будет произведен поиск по имени.
В системе могут существовать и шрифты с другими кодировками. Если приложение использует шрифт с неизвестной кодировкой, то оно не должно пытаться перевести строки, которые должны быть представлены этим шрифтом.
Задавая имя шрифта (поле IfFaceName), убедитесь, что значение lfCharSet совпадает с кодировкой шрифта с именем, указанном в lfFaceName.

Поле lfOutPrecision определяет насколько точно шрифт должен соответствовать запрашиваемым параметрам шрифта, таким как высота, ширина, ориентация и др. Оно может принимать следующие значения:

OUT_CHARACTER_PRECIS Не используется.
OUT_DEFAULT_PRECIS Определяет механизм выбора шрифта, принятый по умолчанию
OUT_DEVICE_PRECIS Указывает, что должен быть выбран системный шрифт (Device font), если в системе установлено несколько шрифтов с одним и тем же именем.
OUT_OUTLINE_PRECIS Windows NT: Указывает, что должен быть выбран шрифт TrueType или векторный шрифт.
Windows 95: Значение не используется.
OUT_RASTER_PRECIS Указывает, что должен быть выбран растровый шрифт, если в системе установлено несколько шрифтов с одним и тем же именем.
OUT_STRING_PRECIS Это значение не используется механизмом выбора шрифтов, но оно возвращается при перечислении растровых шрифтов.
OUT_STROKE_PRECIS Windows NT: Это значение не используется механизмом выбора шрифтов, но возвращается при перечислении шрифтов TrueType, растровых или векторных шрифтов.
Windows 95: Используется при выборе векторных шрифтов, а также возвращается при перечислении векторных шрифтов или шрифтов TrueType.
OUT_TT_ONLY_PRECIS Указывает, что должен быть выбран шрифт TrueType. Если в системе не установлено ни одного шрифта TrueType, то используется механизм выбора шрифтов, принятый по умолчанию.
OUT_TT_PRECIS Указывает, что должен быть выбран шрифт TrueType, если в системе установлено несколько шрифтов с одним и тем же именем.

Приложение может использовать значения OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, и OUT_TT_PRECIS для управления механизмом выбора шрифта, если в ОС установлено несколько шрифтов с одним и тем же именем.

Поле lfClipPrecision Определяет механизм отсечения символов, т.е. как отсекаются символы, частично находящиеся вне области вывода. Может принимать следующие значения: CLIP_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, CLIP_STROKE_PRECIS.

Поле lfQuality определяет качество вывода, т.е. насколько качественно graphics device interface (GDI) должно попытаться найти шрифт. Может принимать следующие значения:

DEFAULT_QUALITY Качество вывода не имеет значения.
DRAFT_QUALITY Качество вывода менее важно, чем при использовании значения PROOF_QUALITY. Для растровых шрифтов разрешается масштабирование. Жирное, курсивное, подчеркнутое и перечеркнутое начертания шрифта могут быть синтезированы при необходимости.
PROOF_QUALITY Качество символов более важно, чем сходство остальных логических атрибутов шрифта. Для растровых шрифтов (GDI fonts) масштабирование недоступно и выбирается ближайший по размеру шрифт. Может быть выбран шрифт не совсем требуемого размера, зато качество шрифта высокое и нет искажений при выводе символов. Жирное, курсивное, подчеркнутое и перечеркнутое начертания шрифта могут быть синтезированы при необходимости.

Поле lfPitchAndFamily определяет тип и семейство шрифта. Два младших бита определяют тип шрифта и могут принимать следующие значения: DEFAULT_PITCH, FIXED_PITCH (непропорциональный шрифт, т.е. все символы имеют одинаковый размер), VARIABLE_PITCH (пропорциональный шрифт).
Биты с 4 по 7 определяют семейство шрифта и могут принимать следующие значения:

FF_DECORATIVE Декоративный шрифт, например Old English.
FF_DONTCARE Семейство шрифта не имеет значения.
FF_MODERN Непропорциональный шрифт с засечками (serif) или без, например Pica, Elite, CourierNew®)
FF_ROMAN Пропорциональный шрифт с засечками, например MS® Serif.
FF_SCRIPT Шрифт, походящий на рукописный тескт, например Script, Cursive.
FF_SWISS Пропорциональный шрифт без засечек, например MS® Sans Serif.

Значение поля lfPitchAndFamily может быть получено применением логической операции OR к типу и семейству шрифта.

Поле lfFaceName указывает на строку, оканчивающуюся символом с кодом ноль (null-terminated string), которая определяет имя (typeface name) шрифта. Длина строки не должна превышать 32 символов. Функция Windows EnumFonts() может быть использована для перечисления typeface name всех доступных в настоящее время шрифтов. Если lfFaceName=NULL, то GDI использует typeface, принятый по умолчанию.

Создать шрифт можно с помощью функции
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.

Также создать шрифт можно с помощью функции
BOOL CFont::CreatePointFontIndirect( const LOGFONT* lpLogFont, CDC* pDC = NULL );
Где lpLogFont - указатель на уже знакомую структуру LOGFONT, pDC - указатель на объект контекста устройства, используемый для перевода высоты в lfHeight в логические единицы. Если pDC=NULL, то в качестве контекста устройства используется контекст экрана.

И наконец шрифт можно создать с помощью функции
BOOL CFont::CreatePointFont( int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL );
Где nPointSize - высота шрифта в десятых долях пункта (point). (Например, nPointSize=120 - соответствует шрифту с высотой в 12 пунктов.);
lpszFaceName - CString или указатель на null-terminated string, определяет имя шрифта (Длина строки не должна превышать 30 символов. Функция Windows EnumFontFamilies() может быть использована для перечисления всех доступных в данный момент шрифтов. Если lpszFaceName=NULL, то GDI использует шрифт, независящий от устройства);
pDC - определяется, как и в предыдущей функции.

Пример


void CCreateFontIndirectView::OnPaint()
{
CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here
CRect rect;
GetClientRect ( &rect ) ;
CFont font;
int angle=450;
LOGFONT lf = { 32, 0, angle, angle, FW_BOLD, 0, 0, 0,
RUSSIAN_CHARSET, OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH | FF_ROMAN, NULL } ;
font.CreateFontIndirect( &lf ) ;
CFont * pFont = dc.SelectObject( &font) ;

CString str("Hello world");

rect.OffsetRect( 0, rect.Height()/3 );
dc.DrawText( str, rect, DT_NOCLIP ) ;

rect.OffsetRect( rect.Width()/3, rect.Height()/3 );
dc.SetBkMode( TRANSPARENT );
dc.DrawText( str, rect, DT_NOCLIP ) ;

dc.SelectObject ( pFont ) ;
font.DeleteObject ( ) ;

// Do not call CView::OnPaint() for painting messages
}