Simulating Check Boxes in a Menu

This topic contains an example that shows how to simulate check boxes in a menu. The example contains a Character menu whose items allow the user to set the bold, italic, and underline attributes of the current font. When a font attribute is in effect, a check mark is displayed in the check box next to the corresponding menu item; otherwise, an empty check box is displayed next to the item.

The example replaces the default check-mark bitmap with two bitmaps: a bitmap with a checked box and the bitmap with an empty box. The checked check box bitmap is displayed next to the Bold, Italic, or Underline menu item when the item's check-mark attribute is set to MF_CHECKED. The unchecked or empty check box bitmap is displayed when the check-mark attribute is set to MF_UNCHECKED.

Windows provides a predefined bitmap that contains the images used for check boxes and radio buttons. The example isolates the checked and empty check boxes, copies them to two separate bitmaps, and then uses them as the checked and unchecked bitmaps for items in the Character menu.

To retrieve the handle of the system-defined check box bitmap, the example calls the LoadBitmap function, specifying NULL as the hInstance parameter and OBM_CHECKBOXES as the lpBitmapName parameter. Because the images in the bitmap are all the same size, the example can isolate them by dividing the bitmap's width and height by the number of images in its rows and columns.

The following portion of a resource-definition file shows how the menu items in the Character menu are defined. Note that no font attributes are in effect initially, so the check-mark attribute for the Regular item is set to checked and, by default, the check-mark attribute of the remaining items is set to unchecked.

#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

Here are the relevant contents of the application's header file.

// Menu-item identifiers

#define IDM_REGULAR 0x1

#define IDM_BOLD 0x2

#define IDM_ITALIC 0x4

#define IDM_ULINE 0x8

// Check-mark flags

#define CHECK 1

#define UNCHECK 2

// Font-attribute mask

#define ATTRIBMASK 0xe

// Function prototypes

LRESULT APIENTRY MainWndProc(HWND, UINT, WPARAM, LPARAM);

HBITMAP GetMyCheckBitmaps(UINT);

BYTE CheckOrUncheckMenuItem(BYTE, HMENU);

The following example shows the portions of the window procedure that create the check-mark bitmaps; set the check-mark attribute of the Bold, Italic, and Underline menu items; and destroy check-mark bitmaps.

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

static HBITMAP hbmpCheck; // handle of checked bitmap

static HBITMAP hbmpUncheck; // handle of unchecked bitmap

static HMENU hmenu; // handle of main menu

BYTE fbFontAttrib; // font-attribute flags

switch (uMsg) {

case WM_CREATE:

// Call the application-defined GetMyCheckBitmaps

// function to get the predefined checked and

// unchecked check box bitmaps.

hbmpCheck = GetMyCheckBitmaps(CHECK);

hbmpUncheck = GetMyCheckBitmaps(UNCHECK);

// Set the checked and unchecked bitmaps for the menu

// items.

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)) {

// Process the menu commands.

case IDM_REGULAR:

case IDM_BOLD:

case IDM_ITALIC:

case IDM_ULINE:

// CheckOrUncheckMenuItem is an application-

// defined function that sets the menu item

// check marks and returns the user-selected

// font attributes.

fbFontAttrib = CheckOrUncheckMenuItem(

(BYTE) LOWORD(wParam), hmenu);

.

. // Set the font attributes.

.

return 0;

.

. // Process other command messages.

.

default:

break;

}

break;

.

. // Process other window messages.

.

case WM_DESTROY:

// Destroy the checked and unchecked bitmaps.

DeleteObject(hbmpCheck);

DeleteObject(hbmpUncheck);

PostQuitMessage(0);

break;

default:

return DefWindowProc(hwndMain, uMsg, wParam, lParam);

}

return NULL;

}

HBITMAP GetMyCheckBitmaps(fuCheck)

UINT fuCheck; // CHECK or UNCHECK flag

{

COLORREF crBackground; // background color

HBRUSH hbrBackground; // background brush

HBRUSH hbrTargetOld; // original background brush

HDC hdcSource; // source device context

HDC hdcTarget; // target device context

HBITMAP hbmpCheckboxes; // handle of check-box bitmap

BITMAP bmCheckbox; // structure for bitmap data

HBITMAP hbmpSourceOld; // handle of original source bitmap

HBITMAP hbmpTargetOld; // handle of original target bitmap

HBITMAP hbmpCheck; // handle of check-mark bitmap

RECT rc; // rectangle for check-box bitmap

DWORD dwCheckXY; // dimensions of check-mark bitmap

WORD wBitmapX; // width of check-mark bitmap

WORD wBitmapY; // height of check-mark bitmap

// Get the menu background color and create a solid brush

// with that color.

crBackground = GetSysColor(COLOR_MENU);

hbrBackground = CreateSolidBrush(crBackground);

// Create memory device contexts for the source and

// destination bitmaps.

hdcSource = CreateCompatibleDC((HDC) NULL);

hdcTarget = CreateCompatibleDC(hdcSource);

// Get the size of the Windows default check-mark bitmap and

// create a compatible bitmap of the same size.

dwCheckXY = GetMenuCheckMarkDimensions();

wBitmapX = LOWORD(dwCheckXY);

wBitmapY = LOWORD(dwCheckXY);

hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX,

wBitmapY);

// Select the background brush and bitmap into the target DC.

hbrTargetOld = SelectObject(hdcTarget, hbrBackground);

hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck);

// Use the selected brush to initialize the background color

// of the bitmap in the target device context.

PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY);

// Load the predefined check box bitmaps and select it

// into the source DC.

hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL,

(LPTSTR) OBM_CHECKBOXES);

hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes);

// Fill a BITMAP structure with information about the

// check box bitmaps, and then find the upper-left corner of

// the unchecked check box or the checked check box.

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);

// Copy the appropriate bitmap into the target DC. If the

// check-box bitmap is larger than the default check-mark

// bitmap, use StretchBlt to make it fit; otherwise, just

// copy it.

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);

// Select the old source and destination bitmaps into the

// source and destination DCs, and then delete the DCs and

// the background brush.

SelectObject(hdcSource, hbmpSourceOld);

SelectObject(hdcTarget, hbrTargetOld);

hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld);

DeleteObject(hbrBackground);

DeleteObject(hdcSource);

DeleteObject(hdcTarget);

// Return the handle of the new check-mark bitmap.

return hbmpCheck;

}

BYTE CheckOrUncheckMenuItem(bMenuItemID, hmenu)

BYTE bMenuItemID;

HMENU hmenu;

{

DWORD fdwMenu;

static BYTE fbAttributes;

switch (bMenuItemID) {

case IDM_REGULAR:

// Whenever the Regular menu item is selected, add a

// check mark to it and then remove check marks from

// any font-attribute menu items.

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:

// Toggle the check mark for the selected menu item and

// set the font attribute flags appropriately.

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;

}

// If any font attributes are currently selected,

// remove the check mark from the Regular menu item;

// if no attributes are selected, add a check mark

// to the Regular menu item.

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;

}

}

Software for developers
Delphi Components
.Net Components
Software for Android Developers
More information resources
MegaDetailed.Net
Unix Manual Pages
Delphi Examples
Databases for Amazon shops developers
Amazon Categories Database
Browse Nodes Database