Эта тема содержит пример, который показывает, как моделировать окошки для флажка "галочкой" в меню. Пример содержит меню Character (Символ), пункты которого позволяют пользователю устанавливать атрибуты текущего шрифта, такие как полужирный, курсивный и подчеркнутый. Когда атрибут шрифта действует, галочка отображается в окошке для флажка рядом с соответствующим пунктом меню; иначе, рядом с этим пунктом отображается пустое окошко для флажка.
Пример заменяет заданный по умолчанию точечный рисунок "галочки " на два точечных рисунка (значка): точечный рисунок с установленным в окне маркером и точечным рисунком с пустым окном (без маркера). Точечный рисунок окошка для маркера отображается рядом с пунктом меню Bold (Полужирный), Italic (Курсивный) или Underline (Подчеркнутый), когда атрибут "галочки " пункта установлен в значение MF_CHECKED. Снятый маркер "галочки" или пустой точечный рисунок окошка для маркера отображается тогда, когда атрибут "галочки " установлен в значение MF_UNCHECKED.
Windows предоставляет предопределенный точечный рисунок (значок), который содержит изображения, используемые для окошек с маркером "галочка" и радио-кнопок. Пример разделяет пустые окошки для "галочки" и с маркером, копирует их в два отдельных точечных рисунка (значки), а затем использует их как значки установки и снятия отметки "галочкой" для пунктов в меню Character. (Символ).
Чтобы получить дескриптор заданного системой точечного рисунка (значка) окошка для флажка, пример вызывает функцию LoadBitmap, устанавливая значение ПУСТО (NULL) в параметре hInstance и OBM_CHECKBOXES в параметре lpBitmapName. Поскольку все изображения значков одного и того же размера, пример может разделять их, поделив ширину и высоту точечного рисунка на число изображений в строках и столбцах.
Нижеследующая часть файла определения ресурса показывает, как определены пункты меню в меню Character. Обратите внимание!, что сначала атрибуты шрифта не действуют, так как атрибут "галочки " для пункта Обычный (Regular) установлен в отмеченное "галочкой" состояние, а, по умолчанию, атрибут "галочки " оставшихся пунктов установлен в состояние без "галочки".
#include "men3.h" MainMenu MENU BEGIN POPUP "&Character" BEGIN MENUITEM "&Regular", IDM_REGULAR, CHECKED MENUITEM SEPARATOR MENUITEM "&Bold", IDM_BOLD MENUITEM "&Italic", IDM_ITALIC MENUITEM "&Underline", IDM_ULINE END END
Здесь находится относящееся к делу содержание заголовочного файла прикладной программы.
// Идентификаторы пунктов меню #define IDM_REGULAR 0x1 #define IDM_BOLD 0x2 #define IDM_ITALIC 0x4 #define IDM_ULINE 0x8 // Флажки - маркеры #define CHECK 1 #define UNCHECK 2 // Маска атрибута шрифта #define ATTRIBMASK 0xe // Прототипы функций LRESULT APIENTRY MainWndProc(HWND, UINT, WPARAM, LPARAM); HBITMAP GetMyCheckBitmaps(UINT); BYTE CheckOrUncheckMenuItem(BYTE, HMENU);
Следующий пример показывает части оконной процедуры, которые создают точечные рисунки (значки) "галочки "; устанавливает атрибут "галочки" пунктов меню Bold (Полужирный), Italic (Курсивный) и Underline(Подчеркнутый); и уничтожает значки "галочки".
LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam) HWND hwndMain; UINT uMsg; WPARAM wParam; LPARAM lParam; { static HBITMAP hbmpCheck; // дескриптор значка установленной «галочки» static HBITMAP hbmpUncheck; // дескриптор значка без «галочки» static HMENU hmenu; // дескриптор главного окна BYTE fbFontAttrib; // флажки атрибутов шрифта switch (uMsg) { case WM_CREATE: // Вызовем определяемую программой функцию GetMyCheckBitmaps, //, чтобы получить предопределенные точечные рисунки окошка для // установки и снятия отметки "галочкой". hbmpCheck = GetMyCheckBitmaps(CHECK); hbmpUncheck = GetMyCheckBitmaps(UNCHECK); // Установим значки для маркера и снятия маркера // "галочки" для пунктов меню. hmenu = GetMenu(hwndMain); SetMenuItemBitmaps(hmenu, IDM_BOLD, MF_BYCOMMAND, hbmpUncheck, hbmpCheck); SetMenuItemBitmaps(hmenu, IDM_ITALIC, MF_BYCOMMAND, hbmpUncheck, hbmpCheck); SetMenuItemBitmaps(hmenu, IDM_ULINE, MF_BYCOMMAND, hbmpUncheck, hbmpCheck); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { // Обработка команд меню. case IDM_REGULAR: case IDM_BOLD: case IDM_ITALIC: case IDM_ULINE: // CheckOrUncheckMenuItem – функция, определяемая // прикладной программой, которая устанавливает "галочки" // пунктам меню и возвращает выбранный пользователем // атрибут шрифта. fbFontAttrib = CheckOrUncheckMenuItem( (BYTE) LOWORD(wParam), hmenu); . . // Установим атрибуты шрифта. . return 0; . . // Обработаем другие командные сообщения. . default: break; } break; . . // Обработаем другие сообщения окна. . case WM_DESTROY: // Разрушим значки установки и снятия маркера "галочки". DeleteObject(hbmpCheck); DeleteObject(hbmpUncheck); PostQuitMessage(0); break; default: return DefWindowProc(hwndMain, uMsg, wParam, lParam); } return NULL; } HBITMAP GetMyCheckBitmaps(fuCheck) UINT fuCheck; // флажки CHECK или UNCHECK { COLORREF crBackground; // цвет фона HBRUSH hbrBackground; // кисть фона HBRUSH hbrTargetOld; // первоначальная кисть фона HDC hdcSource; // исходный контекст устройства HDC hdcTarget; // контекст устройства цели HBITMAP hbmpCheckboxes; // дескриптор значка маркера BITMAP bmCheckbox; // структура для данных значка HBITMAP hbmpSourceOld; // дескриптор значка первоисточника HBITMAP hbmpTargetOld; // дескриптор первоначального целевого значка HBITMAP hbmpCheck; // дескриптор значка маркера RECT rc; // прямоугольник для точечного рисунка окна маркера DWORD dwCheckXY; // размеры значка маркера WORD wBitmapX; // ширина значка маркера WORD wBitmapY; // высота значка маркера // Получим цвет фона меню и создадим объемную кисть с этим цветом. crBackground = GetSysColor(COLOR_MENU); hbrBackground = CreateSolidBrush(crBackground); // Создадим контекст устройства в памяти для значков источника и цели. hdcSource = CreateCompatibleDC((HDC) NULL); hdcTarget = CreateCompatibleDC(hdcSource); // Получим размер значка "галочки ", который Windows // устанавливает по умолчанию и создадим совместимый точечный // рисунок (значок) того же самого размера. dwCheckXY = GetMenuCheckMarkDimensions(); wBitmapX = LOWORD(dwCheckXY); wBitmapY = LOWORD(dwCheckXY); hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX, wBitmapY); // Выберем кисть фона и значок в целевом значке. hbrTargetOld = SelectObject(hdcTarget, hbrBackground); hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck); // Используем выбранную кисть, чтобы инициализировать цвет фона // Точечного рисунка (значка) в целевом контексте устройства. PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY); // Загрузим предопределенные точечные рисунки окошка // для флажка и выберем его в исходном DC. hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL, (LPTSTR) OBM_CHECKBOXES); hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes); // Заполним структуру BITMAP информацией о точечном рисунке // окошка для флажка, а затем найдем левый верхний угол окошка для установки или снятия маркера (флажка) "галочки". GetObject(hbmpCheckboxes, sizeof(BITMAP), &bmCheckbox); if (fuCheck == UNCHECK) { rc.left = 0; rc.right = (bmCheckbox.bmWidth / 4); } else { rc.left = (bmCheckbox.bmWidth / 4); rc.right = (bmCheckbox.bmWidth / 4) * 2; } rc.top = 0; rc.bottom = (bmCheckbox.bmHeight / 3); //Копируем соответствующий точечный рисунок (значок) в целевом DC. // Если точечный рисунок (значок) переключателя больше, чем заданный // по умолчанию значок "галочки", используем StretchBlt,чтобы подогнать // его по размерам; теперь копируем его. if (((rc.right - rc.left) > (int) wBitmapX) || ((rc.bottom - rc.top) > (int) wBitmapY)) StretchBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, hdcSource, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SRCCOPY); else BitBlt(hdcTarget, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdcSource, rc.left, rc.top, SRCCOPY); // Выберем старый исходный и целевой точечные рисунки // в исходном и целевом DC, а затем удалим DC и кисть фона. SelectObject(hdcSource, hbmpSourceOld); SelectObject(hdcTarget, hbrTargetOld); hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld); DeleteObject(hbrBackground); DeleteObject(hdcSource); DeleteObject(hdcTarget); // Возвратим дескриптор нового точечного рисунка "галочки ". return hbmpCheck; } BYTE CheckOrUncheckMenuItem(bMenuItemID, hmenu) BYTE bMenuItemID; HMENU hmenu; { DWORD fdwMenu; static BYTE fbAttributes; switch (bMenuItemID) { case IDM_REGULAR: // Всякий раз, когда выбран пункт меню Regular, // добавим к нему галочку, а затем удалим галочки из // любого пункта меню атрибута шрифта. CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND | MF_CHECKED); if (fbAttributes & ATTRIBMASK) { CheckMenuItem(hmenu, IDM_BOLD, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hmenu, IDM_ITALIC, MF_BYCOMMAND | MF_UNCHECKED); CheckMenuItem(hmenu, IDM_ULINE, MF_BYCOMMAND | MF_UNCHECKED); } fbAttributes = IDM_REGULAR; return fbAttributes; case IDM_BOLD: case IDM_ITALIC: case IDM_ULINE: // Переключим галочку для выбранного пункта меню и // установим флажки атрибута шрифта соответственно. fdwMenu = GetMenuState(hmenu, (UINT) bMenuItemID, MF_BYCOMMAND); if (!(fdwMenu & MF_CHECKED)) { CheckMenuItem(hmenu, (UINT) bMenuItemID, MF_BYCOMMAND | MF_CHECKED); fbAttributes |= bMenuItemID; } else { CheckMenuItem(hmenu, (UINT) bMenuItemID, MF_BYCOMMAND | MF_UNCHECKED); fbAttributes ^= bMenuItemID; } // Если какие-либо атрибуты шрифта в настоящее время // выбраны, удалим галочку из пункта меню Regular; если // никакие атрибуты не выбраны, добавим галочку к пункту // меню Regular. if (fbAttributes & ATTRIBMASK) { CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND | MF_UNCHECKED); fbAttributes &= (BYTE) ~IDM_REGULAR; } else { CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND | MF_CHECKED); fbAttributes = IDM_REGULAR; } return fbAttributes; } }