本主题中的示例将自定义复选标记位图分配给两个菜单中的菜单项。第一个菜单中的菜单项指定字符属性:粗体,斜体和下划线。可以选择或取消选中每个菜单项。对于这些菜单项,示例使用类似于复选框控件的已选中和未检查状态的复选标记位图。
第二个菜单中的菜单项指定段落对齐设置:左,中,右。在任何给定的时间只检查这些菜单项之一。对于这些菜单项,示例使用类似于单选按钮控件的已检查和未检查状态的复选标记位图。
窗口过程通过调用应用程序定义的OnCreate函数处理WM_CREATE消息。OnCreate创建四个复选标记位图,然后使用SetMenuItemBitmaps功能将它们分配到相应的菜单项。
要创建每个位图,OnCreate调用应用程序定义的CreateMenuBitmaps函数,指定一个指向位图的绘图函数的指针。CreateMenuBitmaps创建所需大小的单色位图,将其选择到内存设备上下文中,并擦除背景。然后调用指定的绘图函数来填充前景。
四个应用程序定义的绘图函数是DrawCheck,DrawUncheck,DrawRadioCheck和DrawRadioUncheck。它们分别绘制一个带有X,一个空矩形,一个包含较小的填充椭圆的椭圆和一个空椭圆的矩形。
窗口过程通过删除复选标记位图来处理WM_DESTROY消息。它使用GetMenuItemInfo函数检索每个位图句柄,然后将句柄传递给DeleteObject函数。
当用户选择菜单项时,WM_COMMAND消息被发送到所有者窗口。对于字符菜单中的菜单项,窗口过程调用应用程序定义的CheckCharacterItem函数。对于段落菜单中的项目,窗口过程调用应用程序定义的CheckParagraphItem函数。
字符菜单上的每个项目都可以单独检查和取消选中。因此,CheckCharacterItem只需切换指定的菜单项的检查状态。首先,函数调用GetMenuItemInfo函数来获取当前菜单项的状态。然后它切换MFS_CHECKED状态标志,并通过调用SetMenuItemInfo功能设置新状态。
与角色属性不同,一次只能选择一个段落对齐。因此,CheckParagraphItem检查指定的菜单项,并从菜单上的所有其他项目中删除复选标记。为此,它调用CheckMenuRadioItem函数。
以下是应用程序头文件的相关部分。
//字符菜单的菜单项标识符
#define IDM_BOLD 11
#define IDM_ITALIC 12
#define IDM_UNDERLINE 13
//段落菜单的菜单项标识符
//段落菜单的菜单项标识符
#define IDM_LEFT 21
#define IDM_CENTER 22
#define IDM_RIGHT 23
// Function-pointer type for drawing functions
//绘图函数的函数指针类型
typedef VOID (WINAPI * DRAWFUNC)(HDC hdc, SIZE size);
以下是应用程序的窗口过程和相关功能的相关部分。
LRESULT CALLBACK MainWindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
if(!OnCreate(hwnd))
)
{
开关(uMsg){
case WM_CREATE:
if(!OnCreate(hwnd))
return -1;
break;
case WM_DESTROY:
OnDestroy(hwnd);
PostQuitMessage(0);
break;
case WM_COMMAND:
开关(LOWORD(wParam)){
case IDM_BOLD:
case IDM_ITALIC:
case IDM_UNDERLINE:
CheckCharacterItem(hwnd, LOWORD(wParam));
break;
case IDM_LEFT:
case IDM_CENTER:
case IDM_RIGHT:
CheckParagraphItem(hwnd, LOWORD(wParam));
break;
.
. //在这里处理其他命令
.
}
break;
.
. //处理其他消息。
.
默认:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
VOID WINAPI CheckCharacterItem(HWND hwnd,UINT uID)
{
HMENU hmenuBar = GetMenu(hwnd);
HMENU hmenuPopup;
MENUITEMINFO mii;
//获取字符菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//获取指定菜单项的状态。
mii.fMask = MIIM_STATE; //获取信息
GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);
//切换检查状态。
mii.fState ^= MFS_CHECKED;
SetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);
}
VOID WINAPI CheckParagraphItem(HWND hwnd,UINT uID)
{
HMENU hmenuBar = GetMenu(hwnd);
HMENU hmenuPopup;
MENUITEMINFO mii;
//获取段落菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//检查指定的项目,并取消选中所有其他项目。
CheckMenuRadioItem(
hmenuPopup, //菜单的句柄
IDM_LEFT, //范围内的第一个项目
IDM_RIGHT, //范围内的最后一个项目
uID, //要检查的项目
MF_BYCOMMAND // ID,而不是位置
);
}
BOOL WINAPI OnCreate(HWND hwnd)
{
HMENU hmenuBar = GetMenu(hwnd);
HMENU hmenuPopup;
MENUITEMINFO mii;
UINT uID;
HBITMAP hbmChecked;
HBITMAP hbmUnchecked;
//获取字符菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//创建检查和未检查的位图。
hbmChecked = CreateMenuBitmap(DrawCheck);
hbmUnchecked = CreateMenuBitmap(DrawUncheck);
//设置每个菜单项的复选标记位图。
for (uID = IDM_BOLD; uID <= IDM_UNDERLINE; uID++) {
SetMenuItemBitmaps(hmenuPopup,uID,MF_BYCOMMAND,
hbmUnchecked, hbmChecked);
}
//获取段落弹出菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//创建检查和未检查的位图。
hbmChecked = CreateMenuBitmap(DrawRadioCheck);
hbmUnchecked = CreateMenuBitmap(DrawRadioUncheck);
//设置每个菜单项的复选标记位图。
for (uID = IDM_LEFT; uID <= IDM_RIGHT; uID++) {
SetMenuItemBitmaps(hmenuPopup,uID,MF_BYCOMMAND,
hbmUnchecked, hbmChecked);
}
//最初检查IDM_LEFT段落项。
CheckMenuRadioItem(hmenuPopup,IDM_LEFT,IDM_RIGHT,
IDM_LEFT, MF_BYCOMMAND);
return TRUE;
}
HBITMAP WINAPI CreateMenuBitmap(DRAWFUNC lpfnDraw)
{
//创建与桌面窗口的DC兼容的DC。
HWND hwndDesktop = GetDesktopWindow();
HDC hdcDesktop = GetDC(hwndDesktop);
HDC hdcMem = CreateCompatibleDC(hdcDesktop);
//确定所需的位图大小。
DWORD dwExt = GetMenuCheckMarkDimensions();
SIZE size = { LOWORD(dwExt), HIWORD(dwExt) };
//创建一个单色位图并选择它。
HBITMAP hbm = CreateBitmap(size.cx, size.cy, 1, 1, NULL);
HBITMAP hbmOld = SelectObject(hdcMem, hbm);
//擦除背景并调用绘图功能。
PatBlt(hdcMem, 0, 0, size.cx, size.cy, WHITENESS);
(*lpfnDraw)(hdcMem, size);
// 清理。
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
ReleaseDC(hwndDesktop, hdcDesktop);
return hbm;
}
VOID WINAPI DrawCheck(HDC hdc,SIZE size)
{
HBRUSH hbrOld;
hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc, 0, 0, size.cx, size.cy);
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, size.cx, size.cy);
MoveToEx(hdc, 0, size.cy - 1, NULL);
LineTo(hdc, size.cx - 1, 0);
SelectObject(hdc, hbrOld);
}
VOID WINAPI DrawUncheck(HDC hdc,SIZE大小)
{
HBRUSH hbrOld;
hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
Rectangle(hdc, 0, 0, size.cx, size.cy);
SelectObject(hdc, hbrOld);
}
VOID WINAPI DrawRadioCheck(HDC hdc,SIZE大小)
{
HBRUSH hbrOld;
hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
Ellipse(hdc, 0, 0, size.cx, size.cy);
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Ellipse(hdc, 2, 2, size.cx - 2, size.cy - 2);
SelectObject(hdc, hbrOld);
}
VOID WINAPI DrawRadioUncheck(HDC hdc,SIZE size)
{
HBRUSH hbrOld;
hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));
Ellipse(hdc, 0, 0, size.cx, size.cy);
SelectObject(hdc, hbrOld);
}
VOID WINAPI OnDestroy(HWND hwnd)
{
HMENU hmenuBar = GetMenu(hwnd);
HMENU hmenuPopup;
MENUITEMINFO mii;
//获取字符菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//获取复选标记位图并将其删除。
mii.fMask = MIIM_CHECKMARKS;
GetMenuItemInfo(hmenuPopup, IDM_BOLD, FALSE, &mii);
DeleteObject(mii.hbmpChecked);
DeleteObject(mii.hbmpUnchecked);
//获取段落菜单的句柄。
mii.fMask = MIIM_SUBMENU; //获取信息
GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);
hmenuPopup = mii.hSubMenu;
//获取复选标记位图并将其删除。
mii.fMask = MIIM_CHECKMARKS;
GetMenuItemInfo(hmenuPopup, IDM_LEFT, FALSE, &mii);
DeleteObject(mii.hbmpChecked);
DeleteObject(mii.hbmpUnchecked);
}