Настройка шрифтов для текстовых строк пункта меню

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

Здесь меню, заданное в файле определения ресурса. Обратите внимание, что строки для пунктов меню 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, чтобы сделать следующее:

Установить флажок MF_OWNERDRAW для пунктов меню.

Установить строки текста для пунктов меню.

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

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

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

В ходе обработки сообщения WM_MEASUREITEM, пример получает ширину и высоту строки пункта меню и копирует эти значения в структуру MEASUREITEMSTRUCT. Windows использует значения ширины и высоты, чтобы вычислить размер меню.

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

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)
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;// протяженность текста пункта меню
DWORD dwCheckXY;// размеры метки «галочка»
WORD wCheckX;// ширина метки «галочка»
int nTextX;// ширина пункта меню
int nTextY;// высота пункта меню
int i;// цикл счета
HFONT hfontOld;// дескриптор старого шрифта
BOOL fSelected = FALSE;// флажок выбора пункта меню

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.


GetTextExtentPoint32(hdc, pmyitem->psz,
lstrlen(pmyitem->psz), &size);
lpmis->itemWidth = size.cx;
lpmis->itemHeight = size.cy;

// В контексте устройства обратно выберем старый
// шрифт, и затем освободим контекст устройства.


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;
}

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


dwCheckXY = GetMenuCheckMarkDimensions();

wCheckX = LOWORD(dwCheckXY);
nTextX = wCheckX + lpdis->rcItem.left;
nTextY = lpdis->rcItem.top;

// Выберите шрифт, связанный с пунктом в контексте
// устройства пункта, а затем нарисуйте строку.


hfontOld = SelectObject(lpdis->hDC, pmyitem->hfont);
ExtTextOut(lpdis->hDC, nTextX, nTextY, ETO_OPAQUE,
&lpdis->rcItem, pmyitem->psz,
lstrlen(pmyitem->psz), 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(fnFont)
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);
}
 
« Предыдущая статья   Следующая статья »