Установка шрифта для текстовых строк пунктов меню
Эта тема содержит пример из прикладной программы, которая использует собственные пункты в меню. Меню содержит пункты, которые устанавливают атрибуты текущего шрифта и они отображаются, используя соответствующий атрибут шрифта.
Здесь меню, заданное в файле определения ресурса.
| Обратите внимание! на то, что строки для пунктов меню Regular (Обычный), Bold (Полужирный), Italic (Курсив) и Underline (Подчеркнутый) назначаются во время выполнения программы, так что их строки пустые в файле определения ресурса. |
MainMenu MENU
BEGIN
POPUP "&Character"
BEGIN
MENUITEM "", IDM_REGULAR
MENUITEM SEPARATOR
MENUITEM "", IDM_BOLD
MENUITEM "", IDM_ITALIC
MENUITEM "", IDM_ULINE
END
END
|
Оконная процедура прикладной программы обрабатывает сообщения, включающие использование собственных пунктов меню. Приложение использует сообщение
WM_CREATE, чтобы сделать следующее:Дескрипторы текстовых строк и шрифта сохраняются в массиве определяемых программой структур MYITEM. Определяемая программой функция GetAFont создает шрифт, который соответствует атрибутам заданного шрифта и возвращает значение дескриптора шрифта. Дескрипторы разрушаются в ходе обработки сообщения WM_DESTROY.
В ходе обработки сообщения WM_MEASUREITEM, пример получает ширину и высоту строки пункта меню и копирует эти значения в структуру MEASUREITEMSTRUCT. Система использует значения ширины и высоты, чтобы вычислить размер меню.
В ходе обработки сообщения WM_DRAWITEM, строка пункта меню рисуется, оставляя место рядом со строкой для значка "галочки ". Если пользователь выбирает этот пункт, цвет выбранного текста и фона используются, чтобы нарисовать пункт.
LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
typedef struct _MYITEM
{
HFONT hfont;
LPSTR psz;
} MYITEM; // структура для шрифта и строки пункта
MYITEM *pmyitem; // указатель на шрифт и строку
static MYITEM myitem[CITEMS]; // массив MYITEMS
static HMENU hmenu; // дескриптор главного окна
static COLORREF crSelText; // цвет текста выбранного пункта
static COLORREF crSelBkgnd; // цвет фона выбранного пункта
COLORREF crText; // цвет текста не выбранного пункта
COLORREF crBkgnd; // цвет фона не выбранного пункта
LPMEASUREITEMSTRUCT lpmis; // указатель на данные пункта
LPDRAWITEMSTRUCT lpdis; // указатель на данные рисуемого пункта
HDC hdc; // дескриптор экранного DC
SIZE size; // протяженность текста пункта меню
WORD wCheckX; // ширина "галочки"
int nTextX; // ширина пункта меню
int nTextY; // высота пункта меню
int i; // счет цикла
HFONT hfontOld; // дескриптор прежнего шрифта
BOOL fSelected = FALSE; // флажок выбора пункта меню
size_t * pcch;
HRESULT hResult;
switch (uMsg)
{
case WM_CREATE:
// Модифицируем пункты меню Regular, Bold, Italic
// и Underline, чтобы сделать их собственными пунктами.
// Свяжем структуру MYITEM с каждым пунктом, которая
// содержит дескрипторы шрифта и строки каждого из них.
hmenu = GetMenu(hwnd);
ModifyMenu(hmenu, IDM_REGULAR, MF_BYCOMMAND |
MF_CHECKED | MF_OWNERDRAW, IDM_REGULAR,
(LPTSTR) &myitem[REGULAR]);
ModifyMenu(hmenu, IDM_BOLD, MF_BYCOMMAND |
MF_OWNERDRAW, IDM_BOLD, (LPTSTR) &myitem[BOLD]);
ModifyMenu(hmenu, IDM_ITALIC, MF_BYCOMMAND |
MF_OWNERDRAW, IDM_ITALIC,
(LPTSTR) &myitem[ITALIC]);
ModifyMenu(hmenu, IDM_ULINE, MF_BYCOMMAND |
MF_OWNERDRAW, IDM_ULINE, (LPTSTR) &myitem[ULINE]);
// Извлечем каждый дескриптор шрифта пункта и скопируем их в
// член hfont структуры MYITEM каждого пункта. Таким же
// образом скопируем в структуры строки каждого пункта.
myitem[REGULAR].hfont = GetAFont(REGULAR);
myitem[REGULAR].psz = "Regular";
myitem[BOLD].hfont = GetAFont(BOLD);
myitem[BOLD].psz = "Bold";
myitem[ITALIC].hfont = GetAFont(ITALIC);
myitem[ITALIC].psz = "Italic";
myitem[ULINE].hfont = GetAFont(ULINE);
myitem[ULINE].psz = "Underline";
// Извлечем цвета текста и фона
// выбираемого текста меню.
crSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
crSelBkgnd = GetSysColor(COLOR_HIGHLIGHT);
return 0;
case WM_MEASUREITEM:
// Извлечем контекст устройства для главного окна.
hdc = GetDC(hwnd);
// Извлечем указатели на пункты меню в структурах
// MEASUREITEMSTRUCT и MYITEM.
lpmis = (LPMEASUREITEMSTRUCT) lParam;
pmyitem = (MYITEM *) lpmis->itemData;
// Выберем шрифт, связанный пунктом в контексте устройства
// главного окна.
hfontOld = SelectObject(hdc, pmyitem->hfont);
// Извлечем ширину и высоту строки пункта,
// а затем скопируем ширину и высоту в членах itemWidth
// и itemHeight структуры MEASUREITEMSTRUCT.
hResult = StringCchLength(pmyitem->psz,
STRSAFE_MAX_CCH, pcch);
if (FAILED(hResult))
{
// Добавим код, который, при завершении ошибкой
// операции, настолько возможно обезопасит систему.
return;
}
GetTextExtentPoint32(hdc, pmyitem->psz,
*pcch, &size);
lpmis->itemWidth = size.cx;
lpmis->itemHeight = size.cy;
// Выберем прежний шрифт обратно в контекст устройства,
// и затем освободим этот DC.
SelectObject(hdc, hfontOld);
ReleaseDC(hwnd, hdc);
return TRUE;
break;
case WM_DRAWITEM:
// Получим указатели на пункты меню в структурах
// DRAWITEMSTRUCT и MYITEM.
lpdis = (LPDRAWITEMSTRUCT) lParam;
pmyitem = (MYITEM *) lpdis->itemData;
// Если пользователь выбрал пункт, чтобы показать пункт,
// используйте цвет текста и фона для выбора.
if (lpdis->itemState & ODS_SELECTED)
{
crText = SetTextColor(lpdis->hDC, crSelText);
crBkgnd = SetBkColor(lpdis->hDC, crSelBkgnd);
fSelected = TRUE;
}
// Помните, что в пункте меню надо оставить место для
// значка "галочки". Извлечем ширину значка и
// добавим ее к ширине пункта меню.
wCheckX = GetSystemMetrics(SM_CXMENUCHECK);
nTextX = wCheckX + lpdis->rcItem.left;
nTextY = lpdis->rcItem.top;
// Выберем шрифт связанный с пунктом в контексте
// устройства пункта, а затем пропишем строку.
hfontOld = SelectObject(lpdis->hDC, pmyitem->hfont);
hResult = StringCchLength(pmyitem->psz,
STRSAFE_MAX_CCH, pcch);
if (FAILED(hResult))
{
// Добавим код, который, при завершении ошибкой
// операции, насколько возможно обезопасит систему.
return;
}
ExtTextOut(lpdis->hDC, nTextX, nTextY, ETO_OPAQUE,
&lpdis->rcItem, pmyitem->psz,
*pcch, NULL);
// Выберем предыдущий шрифт обратно в
// контекст устройства.
SelectObject(lpdis->hDC, hfontOld);
// Возвратим цвет текста и фона в их
// обычное состояние (не выбранное).
if (fSelected)
{
SetTextColor(lpdis->hDC, crText);
SetBkColor(lpdis->hDC, crBkgnd);
}
return TRUE;
// Обработка других сообщений.
case WM_DESTROY:
// Уничтожим дескрипторы шрифта пунктов меню.
for (i = 0; i < CITEMS; i++)
DeleteObject(myitem[i].hfont);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return NULL;
}
HFONT GetAFont(int fnFont)
{
static LOGFONT lf; // структура для информации о шрифте
// Получим дескриптор моноширинного шрифта ANSI и скопируем
// информацию о шрифте в структуру LOGFONT.
GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT),
&lf);
// Установим соответствующие атрибуты шрифта.
if (fnFont == BOLD)
lf.lfWeight = FW_BOLD;
else
lf.lfWeight = FW_NORMAL;
lf.lfItalic = (fnFont == ITALIC);
lf.lfItalic = (fnFont == ULINE);
// Создадим шрифт, а затем возвратим его дескриптор.
return CreateFont(lf.lfHeight, lf.lfWidth,
lf.lfEscapement, lf.lfOrientation, lf.lfWeight,
lf.lfItalic, lf.lfUnderline, lf.lfStrikeOut, lf.lfCharSet,
lf.lfOutPrecision, lf.lfClipPrecision, lf.lfQuality,
lf.lfPitchAndFamily, lf.lfFaceName);
}
|