Графика в меню
До сих пор наши меню состояли только из текстовых строк и разделительных линий, однако вы можете сделать меню из произвольных графических изображений. Если вам не нравится стандартная отметка строк меню при помощи галочки, ее можно заменить на любое графическое изображение (небольшого размера).
Для того чтобы вместо строк в меню расположить графические изображения bitmap, эти изображения надо загрузить из ресурсов или создать другим способом, а затем идентификатор изображения указать в качестве последнего параметра функций AppendMenu или InsertMenu. Необходимо также использовать флаг MF_BITMAP :
AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE1, (LPCSTR)(DWORD)hbmpLine1);
Если вы загрузили bitmap при помощи функции LoadBitmap, не забудьте перед завершением приложения (или после удаления соответствующего меню) удалить bitmap функцией DeleteObject.
Для замены стандартного символа отметки строки меню (галочки) на другой предназначена функция SetMenuItemBitmaps:
BOOL WINAPI SetMenuItemBitmaps(HMENU hmenu, UINT idItem, UINT fuFlags, HBITMAP hbmUnckecked, HBITMAP hbmChecked);
Эта функция выполняет замену символа отметки для строки idItem меню hmenu.
Для параметра fuFlags можно использовать два значения - MF_BYCOMMAND и MF_BYPOSITION . Если указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, для которого выполняется замена символа отметки. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню.
Параметр hbmUnckecked представляет собой идентификатор изображения, которое будет расположено слева от неотмеченной строки меню, параметр hbmChecked - идентификатор изображения символа отметки.
Любой из последних параметров или оба можно указывать как NULL. В этом случае будет использовано изображение по умолчанию (т. е. слева от неотмеченной строки не будет никакого изображения, слева от отмеченной - галочка).
Однако есть небольшая тонкость. Вы не можете использовать для отметки строк меню изображения bitmap любого размера.
Нужные размеры изображения необходимо определить при помощи функции GetMenuCheckMarkDimensions :
DWORD WINAPI GetMenuCheckMarkDimensions(void);
Младшее слово возвращаемого значения содержит ширину изображения, старшее - высоту:
DWORD dwMark; WORD wWidth, wHeight; dwMark = GetMenuCheckMarkDimensions(); wWidth = LOWORD(dwMark); wHeight = HIWORD(dwMark);
Тонкость заключается в том, что на момент трансляции исходного текста приложения вы не можете знать требуемые размеры изображения. Так как на этапе сборки загрузочного модуля приложения размеры изображения неизвестны, вы (строго говоря) не можете просто загрузить соответствующие изображения bitmap из ресурсов приложения.
Выход заключается в том, чтобы в процессе инициализации приложения определить требуемые размеры изображения, вызвав функцию GetMenuCheckMarkDimensions, а затем подготовить нужные изображения bitmap в памяти. Однако, так как мы еще не рассказывали вам подробно об изображениях bitmap, в примере GMENU, приведенном в следующем разделе, мы для простоты (данная глава посвящена меню, а не изображениям bitmap) все-таки загрузили изображения размером 10 х 10 пикселов из ресурсов.
При создании строки меню вы можете указать константу MF_OWNERDRAW. В этом случае функция окна, работающая с данным меню, должна будет сама нарисовать строку меню. Можно нарисовать любое изображение.
Перед тем как отобразить меню, содержащее строки со стилем MF_OWNERDRAW , операционная система Windows посылает в функцию окна сообщение WM_MEASUREITEM . В ответ на это сообщение функция должна сообщить Windows размеры окна, необходимые для изображения строки меню.
Когда надо отобразить строку меню, Windows посылает в родительское окно сообщение WM_DRAWITEM . Вместе с этим сообщением передается вся информация, необходимая родительскому окну для того чтобы нарисовать строку меню.
Параметр lParam сообщения WM_MEASUREITEM содержит указатель на структуру MEASUREITEMSTRUCT , описанную в файле windows.h:
typedef struct tagMEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData; } MEASUREITEMSTRUCT;
В этом же файле описаны ближний и дальний указатели на эту структуру:
typedef MEASUREITEMSTRUCT NEAR* PMEASUREITEMSTRUCT; typedef MEASUREITEMSTRUCT FAR* LPMEASUREITEMSTRUCT;
Когда функция окна получает сообщение WM_MEASUREITEM, поле CtlType содержит значение ODT_MENU, в поле itemID находится идентификатор строки меню, а в поле itemData - 32-разрядное значение, переданное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu. Поле CtlID не используется.
Получив сообщение WM_MEASUREITEM, функция окна должна, пользуясь значением указателя из lParam, записать в поле itemWidth ширину строки меню, а в поле itemHeight - высоту строки меню.
Параметр lParam сообщения WM_DRAWITEM содержит указатель на структуру DRAWITEMSTRUCT . Эта структура и соответствующие указатели описаны в файле windows.h следующим образом:
typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; } DRAWITEMSTRUCT; typedef DRAWITEMSTRUCT NEAR* PDRAWITEMSTRUCT; typedef DRAWITEMSTRUCT FAR* LPDRAWITEMSTRUCT;
Приведем назначение отдельных полей структуры DRAWITEMSTRUCT при ее использовании для меню.
Имя поля | Описание |
CtlType | Тип органа управления. Для меню принимает значение ODT_MENU |
CtlID | Идентификатор органа управления. Для меню не используется |
itemID | Идентификатор строки меню |
itemAction | Действия, которые необходимо выполнить при изображении строки меню. Определен в виде отдельных битовых флагов: ODA_DRAWENTIRE - требуется перерисовать всю строку; ODA_FOCUS - этот бит устанавливается в 1, если строка меню получила или потеряла фокус ввода, новое состояние строки можно узнать, проанализировав содержимое поля itemState; ODA_SELECT - изменилось состояние строки меню, для уточнения состояния необходимо использовать поле itemState |
itemState | Вид, в котором необходимо изобразить строку меню. Определен в виде отдельных битовых флагов: ODS_CHECKED - выбрана строка меню; ODS_DISABLED - строка неактивна; ODS_FOCUS - строка получила фокус ввода; ODS_GRAYED - строка меню должна быть изображена серым цветом; ODS_SELECTED - строка выбрана |
hwndItem | Идентификатор меню |
hDC | Контекст устройства, который необходимо использовать для рисования строки меню |
rcItem | Прямоугольные границы, внутри которых необходимо нарисовать строку |
itemData | Содержит 32-битовое значение, полученное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu |