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