47.2.3 Using Menu-Item Bitmaps

A menu item can display a bitmap instead of a string. To use a bitmap as a menu item, you must set the MF_BITMAP flag for the menu item and specify the handle of the bitmap that Windows should display for the menu item. This section describes how to set the MF_BITMAP flag and retrieve the handle of a bitmap.

47.2.3.1 Setting the MF_BITMAP Flag

The MF_BITMAP flag tells Windows that the menu item displays a bitmap rather than a string. A menu item's MF_BITMAP flag must be set at run time—you can't set it in the resource-definition file.

You can use the ModifyMenu, InsertMenu, or AppendMenu function to set the MF_BITMAP flag. Use ModifyMenu to convert an existing item from a string item to a bitmap item. Use the MF_BITMAP flag with the InsertMenu or AppendMenu function to add a new bitmap item to a menu.

47.2.3.2 Creating the Bitmap

When you set the MF_BITMAP flag for a menu item, you must also specify the handle of the bitmap that Windows should display for the menu item. You can provide the bitmap as a bitmap resource, or you can create the bitmap at run time.

To provide a bitmap resource, you can use a resource editor such as ImageEdit to create a bitmap resource, then use a resource compiler to add the bitmap to your application's executable file. At run time, use the LoadBitmap function to load the bitmap and obtain its handle.

Alternatively, you can use GDI functions to create the bitmap at run time. GDI provides several ways to create a bitmap at run time, but applications typically use the following procedure:

Use the CreateCompatibleDC function to create a device context compatible with the device context used by the application's main window.

Use the CreateCompatibleBitmap function to create a bitmap compatible with the application's main window.

Use the SelectObject function to select the bitmap into the compatible device context.

Use GDI drawing functions such as Ellipse and LineTo to draw an image into the bitmap.

Pass the handle of the bitmap to the ModifyMenu, InsertMenu, or AppendMenu function.

For more information on bitmaps, see Chapter 63, “Bitmaps.”

47.2.3.3 Example: Including Lines and Graphs in a Menu

This example shows how to create a menu that contains menu-item bitmaps. It creates two pop-up menus. The first is a “Chart” menu that contains three menu-item bitmaps: a pie chart, a line chart, and a bar chart. The example loads these bitmaps from the application's resource file, then uses the CreatePopupMenu and AppendMenu functions to create the menu and its menu items.

The example also creates a Lines menu that contains bitmaps showing the line styles provided by Windows' predefined pens (see the following illustration). The line-style bitmaps are created at run time by using GDI functions.

Following are the definitions of the bitmap resources in the application's resource-definition file:

PIE BITMAP pie.bmp

LINE BITMAP line.bmp

BAR BITMAP bar.bmp

Following are the relevant portions of the application's header file:

/* Menu-item identifiers */

#define IDM_SOLID PS_SOLID

#define IDM_DASH PS_DASH

#define IDM_DASHDOT PS_DASHDOT

#define IDM_DASHDOTDOT PS_DASHDOTDOT

#define IDM_PIE 1

#define IDM_LINE 2

#define IDM_BAR 3

/* Line-type flags */

#define SOLID 0

#define DOT 1

#define DASH 2

#define DASHDOT 3

#define DASHDOTDOT 4

/* Count of pens */

#define CPENS 5

/* Chart-type flags */

#define PIE 1

#define LINE 2

#define BAR 3

/* Function prototypes */

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

VOID MakeChartMenu(HWND);

VOID MakeLineMenu(HWND, HPEN, HBITMAP);

Following are the portions of the application that create the menus and the menu-item bitmaps:

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

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

static HPEN hpen[CPENS];

static HBITMAP hbmp[CPENS];

int i;

switch (uMsg) {

case WM_CREATE:

/* Create the Chart and Line menus. */

MakeChartMenu(hwnd);

MakeLineMenu(hwnd, hpen, hbmp);

return 0;

.

. /* Process other window messages. */

.

case WM_DESTROY:

for (i = 0; i < CPENS; i++) {

DeleteObject(hbmp[i]);

DeleteObject(hpen[i]);

}

PostQuitMessage(0);

break;

default:

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

}

return NULL;

}

VOID MakeChartMenu(hwnd)

HWND hwnd; /* handle of owner window */

{

HBITMAP hbmpPie; /* handle of pie-chart bitmap */

HBITMAP hbmpLine; /* handle of line-chart bitmap */

HBITMAP hbmpBar; /* handle of bar-chart bitmap */

HMENU hmenuMain; /* handle of main menu */

HMENU hmenuChart; /* handle of chart pop-up menu */

/*

* Load the pie-, line-, and bar-chart bitmaps from the

* resource-definition file.

*/

hbmpPie = LoadBitmap(hinst, MAKEINTRESOURCE(PIE));

hbmpLine = LoadBitmap(hinst, MAKEINTRESOURCE(LINE));

hbmpBar = LoadBitmap(hinst, MAKEINTRESOURCE(BAR));

/*

* Create the Chart pop-up menu and add it to the menu bar.

* Append the Pie, Line, and Bar menu items to the Chart

* pop-up menu.

*/

hmenuMain = GetMenu(hwnd);

hmenuChart = CreatePopupMenu();

AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (UINT) hmenuChart,

"Chart");

AppendMenu(hmenuChart, MF_BITMAP, IDM_PIE, hbmpPie);

AppendMenu(hmenuChart, MF_BITMAP, IDM_LINE, hbmpLine);

AppendMenu(hmenuChart, MF_BITMAP, IDM_BAR, hbmpBar);

return;

}

VOID MakeLineMenu(hwnd, hpen, hbmp)

HWND hwnd;

HPEN hpen[];

HBITMAP hbmp[];

{

HMENU hmenuLines; /* handle of Lines pop-up menu */

HMENU hmenu; /* handle of main menu */

COLORREF crMenuClr; /* menu-item background color */

HBRUSH hbrBackground; /* handle of background brush */

HBRUSH hbrOld; /* handle of previous brush */

LONG lCheckXY; /* dimensions of check mark bitmap */

WORD wLineX; /* width of line bitmaps */

WORD wLineY; /* height of line bitmaps */

HDC hdcMain; /* handle of main window's DC */

HDC hdcLines; /* handle of compatible DC */

HBITMAP hbmpOld; /* handle of previous bitmap */

int i; /* loop counter */

/* Create the Lines pop-up menu. Add it to the menu bar. */

hmenu = GetMenu(hwnd);

hmenuLines = CreatePopupMenu();

AppendMenu(hmenu, MF_STRING | MF_POPUP,

(UINT) hmenuLines, "&Lines");

/* Create a brush for the menu-item background color. */

crMenuClr = GetSysColor(COLOR_MENU);

hbrBackground = CreateSolidBrush(crMenuClr);

/*

* Create a compatible device context for the line bitmaps and

* select the background brush into it.

*/

hdcMain = GetDC(hwnd);

hdcLines = CreateCompatibleDC(hdcMain);

hbrOld = SelectObject(hdcLines, hbrBackground);

/*

* Get the dimensions of the check mark bitmap. The width of

* the line bitmaps will be five times the width of the

* check mark bitmap.

*/

lCheckXY = GetMenuCheckMarkDimensions();

wLineX = LOWORD(lCheckXY) * (WORD) 5;

wLineY = HIWORD(lCheckXY);

/*

* Create the bitmaps and select them, one at a time, into the

* compatible device context. Initialize each bitmap by

* filling it with the menu-item background color.

*/

for (i = 0; i < CPENS; i++) {

hbmp[i] = CreateCompatibleBitmap(hdcMain, wLineX, wLineY);

if (i == 0)

hbmpOld = SelectObject(hdcLines, hbmp[i]);

else

SelectObject(hdcLines, hbmp[i]);

ExtFloodFill(hdcLines, 0, 0, crMenuClr, FLOODFILLBORDER);

}

/* Create the pens. */

hpen[0] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

hpen[1] = CreatePen(PS_DOT, 1, RGB(0, 0, 0));

hpen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));

hpen[3] = CreatePen(PS_DASHDOT, 1, RGB(0, 0, 0));

hpen[4] = CreatePen(PS_DASHDOTDOT, 1, RGB(0, 0, 0));

/*

* Select a pen and a bitmap into the compatible device

* context, draw a line into the bitmap, then append the

* bitmap as an item in the Lines menu.

*/

for (i = 0; i < CPENS; i++) {

SelectObject(hdcLines, hbmp[i]);

SelectObject(hdcLines, hpen[i]);

MoveToEx(hdcLines, 0, wLineY / 2, NULL);

LineTo(hdcLines, wLineX, wLineY / 2);

AppendMenu(hmenuLines, MF_BITMAP, i + 1,

(LPCTSTR) hbmp[i]);

}

/*

* Release the main window's device context and destroy the

* compatible device context. Also destroy the background

* brush.

*/

ReleaseDC(hwnd, hdcMain);

SelectObject(hdcLines, hbrOld);

DeleteObject(hbrBackground);

SelectObject(hdcLines, hbmpOld);

DeleteDC(hdcLines);

return;

}