11.18.5.4 - Моделирование окошек для флажка "галочкой" в меню

Эта тема содержит пример, который показывает, как моделировать окошки для флажка "галочкой" в меню. Пример содержит меню 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;
	}
}

Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Владимир Соковиков - 08.10.2002