Win32 API. Меню
Страница 22. Настройка шрифтов для текстовых строк пункта меню



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

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

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