位图菜单项实例
这个实例新建了两个菜单,各自包含几个位图菜单项。为每个菜单,应用程序添加了相应的菜单名到主窗口的菜单栏中。
首先菜单包含了三个图表类型的菜单项:圆形,线形和条形。这个菜单项位图是作为资源定义的,通过 LoadBitmap函数装入。在菜单栏中关联在"Chart"菜单名。
第二个菜单包含五种线形风格的菜单项,使用 CreatePen函数的: PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT和PS_DASHDOTDOT来建立。应用程序在运行时使用GDI绘画函数来新建位图。在菜单栏中关联在"Lines"菜单名。
在应用程序的窗口过程定义了位图句柄的两个静态数组。一个数组包含了为图表菜单使用的三个位图的句柄。另一个数组包含了为线形菜单使用的五个位图的句柄。当处理WM_CREATE消息时,窗口过程装入图表位图,新建线形位图,并添加它们到相应的菜单项。当处理WM_DESTROY消息时,窗口过程删除全部的位图。
下列是相应应用程序的头文件的部分。
// 菜单项标识符
#define IDM_PIE 1
#define IDM_LINE 2
#define IDM_BAR 3
#define IDM_SOLID 4
#define IDM_DASH 5
#define IDM_DASHDOT 6
#define IDM_DASHDOTDOT 7
// 在图表和线形菜单上项的数目
#define C_LINES 5
#define C_CHARTS 3
// 位图资源标识符
#define IDB_PIE 1
#define IDB_LINE 2
#define IDB_BAR 3
// 线形位图的尺寸
#define CX_LINEBMP 40
#define CY_LINEBMP 10
下列是窗口过程的相应部分。窗口过程通过调用应用程序定义的LoadChartBitmaps,CreateLineBitmaps和AddBitmapMenu函数来初始化。
LRESULT CALLBACK MainWindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
static HBITMAP aHbmLines[C_LINES];
static HBITMAP aHbmChart[C_CHARTS];
int i;
switch (uMsg)
{
case WM_CREATE:
// 调用应用程序定义的函数为图表菜单装入位图并为线形菜单建立那些
LoadChartBitmaps(aHbmChart);
CreateLineBitmaps(aHbmLines);
// 调用应用程序定义的函数去新建包含位图菜单项的菜单。
// 函数同样添加一个菜单名到窗口的菜单栏。
AddBitmapMenu(
hwnd, // menu bar's owner window
"&Chart", // text of menu name on menu bar
IDM_PIE, // ID of first item on menu
aHbmChart, // array of bitmap handles
C_CHARTS // number of items on menu
);
AddBitmapMenu(hwnd, "&Lines", IDM_SOLID,
aHbmLines, C_LINES);
break;
case WM_DESTROY:
for (i = 0; i < C_LINES; i++)
DeleteObject(aHbmLines[i]);
for (i = 0; i < C_CHARTS; i++)
DeleteObject(aHbmChart[i]);
PostQuitMessage(0);
break;
// 在这处理另外的消息
default:
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
}
return 0;
}
应用程序定义的LoadChartBitmaps函数通过调用 LoadBitmap函数来为图表菜单装入位图。如下。
VOID WINAPI LoadChartBitmaps(HBITMAP *paHbm)
{
paHbm[0] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_PIE));
paHbm[1] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_LINE));
paHbm[2] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_BAR));
}
应用程序定义的CreateLineBitmaps函数通过使用GDI绘图函数为线形菜单新建位图。这个函数使用与桌面窗口的设备描述符相同的属性新建一个内存设备描述符。为每一个线形风格,函数新建一个位图,在内存设备描述符中选择它,并绘制它。
VOID WINAPI CreateLineBitmaps(HBITMAP *paHbm)
{
HWND hwndDesktop = GetDesktopWindow();
HDC hdcDesktop = GetDC(hwndDesktop);
HDC hdcMem = CreateCompatibleDC(hdcDesktop);
COLORREF clrMenu = GetSysColor(COLOR_MENU);
HBRUSH hbrOld;
HPEN hpenOld;
HBITMAP hbmOld;
int fnDrawMode;
int i;
// 使用菜单背景色新建一个刷子,并在内存设备描述符中选择它
hbrOld = SelectObject(hdcMem, CreateSolidBrush(clrMenu));
// 新建一个位图。在内存设备描述符中选择各自地去新建并绘制它。
for (i = 0; i < C_LINES; i++)
{
// 新建位图并在设备描述符中选择它
paHbm[i] = CreateCompatibleBitmap(hdcDesktop,
CX_LINEBMP, CY_LINEBMP);
hbmOld = SelectObject(hdcMem, paHbm[i]);
// 使用刷子填充背景
PatBlt(hdcMem, 0, 0, CX_LINEBMP, CY_LINEBMP, PATCOPY);
// 新建画笔并在设备描述符中选择它
hpenOld = SelectObject(hdcMem,
CreatePen(PS_SOLID + i, 1, RGB(0, 0, 0)));
// 绘制线形。去保存背景颜色,并设画笔为白色,使用R2_MASKPEN绘制模式。
fnDrawMode = SetROP2(hdcMem, R2_MASKPEN);
MoveToEx(hdcMem, 0, CY_LINEBMP / 2, NULL);
LineTo(hdcMem, CX_LINEBMP, CY_LINEBMP / 2);
SetROP2(hdcMem, fnDrawMode);
// 删除画笔,并选择旧画笔和位图。
DeleteObject(SelectObject(hdcMem, hpenOld));
SelectObject(hdcMem, hbmOld);
}
// 删除刷子并选择原始刷子。
DeleteObject(SelectObject(hdcMem, hbrOld));
// 删除内存设备描述符并释放桌面设备描述符
DeleteDC(hdcMem);
ReleaseDC(hwndDesktop, hdcDesktop);
}
应用程序定义的AddBitmapMenu函数新建一个菜单并添加指定号数的位图菜单项到它。这时它添加一个相应的菜单名到指定的窗口菜单栏。
VOID WINAPI AddBitmapMenu(
HWND hwnd, // 菜单栏所有者窗口的句柄
LPSTR lpszText, // 在菜单栏上菜单名的文本
UINT uID, // 第一个位图菜单项的ID
HBITMAP *paHbm, // 为菜单项的位图
int cItems) // 位图菜单项的号数
{
HMENU hmenuBar = GetMenu(hwnd);
HMENU hmenuPopup = CreatePopupMenu();
MENUITEMINFO mii;
int i;
// 添加位图菜单项到菜单
for (i = 0; i < cItems; i++)
{
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA;
mii.fType = MFT_BITMAP;
mii.wID = uID + i;
mii.dwTypeData = (LPSTR) (paHbm[i]);
InsertMenuItem(hmenuPopup, i, TRUE, &mii);
}
// 添加一个菜单名到菜单栏
mii.fMask = MIIM_TYPE | MIIM_DATA | MIIM_SUBMENU;
mii.fType = MFT_STRING;
mii.hSubMenu = hmenuPopup;
mii.dwTypeData = lpszText;
InsertMenuItem(hmenuBar,
GetMenuItemCount(hmenuBar), TRUE, &mii);
}