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

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

Здесь меню, заданное в файле определения ресурса. 

Обратите внимание! на то, что строки для пунктов меню 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); 
} 

 

 

Назад в оглавление темы
На главную страницу темы

Hosted by uCoz