Страница 22 из 26
Настройка шрифтов для текстовых строк пункта меню Эта тема содержит пример из прикладной программы, которая использует нарисованные пользователем пункты в меню. Меню содержит пункты, которые устанавливают атрибуты текущего шрифта, а пункты отображаются, используя соответствующий атрибут шрифта. Здесь меню, заданное в файле определения ресурса. Обратите внимание, что строки для пунктов меню 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); } |