📄 coolmenu.cpp
字号:
uMenuID: 菜单资源ID
uToolBarID: 工具栏资源ID,用来提取图标资源
==========================================================================*/
BOOL CCoolMenu::LoadMenu(UINT uMenuID, UINT uToolBarID)
{
ClearData();
BOOL bRet = CMenu::LoadMenu(uMenuID);
if (bRet)
{
//依次设置菜单为自绘风格并设置相关信息-------------
ModifyStyle(GetSafeHmenu(), MDS_TOP_MENU);
//从工具栏中添加图标资源---------------------------
SetImageList(uToolBarID);
}
return bRet;
}
/*========================================================================
功能: 将Windows菜单句柄连接到CCoolMenu对象.
------------------------------------------------
hMenu: 要连接的菜单名柄
uToolBarID: 对应工具栏资源ID,用来提取图标资源
==========================================================================*/
BOOL CCoolMenu::Attach(HMENU hMenu, UINT uToolBarID)
{
ClearData();
BOOL bRet = CMenu::Attach(hMenu);
if (bRet)
{
//依次设置菜单为自绘风格并设置相关信息-------------
ModifyStyle(GetSafeHmenu(), MDS_TOP_MENU);
//从工具栏中添加图标资源---------------------------
SetImageList(uToolBarID);
}
return bRet;
}
/*========================================================================
功能: 断开与菜单句柄的连接并清除相关数据
==========================================================================*/
HMENU CCoolMenu::Detach()
{
ClearData();
return CMenu::Detach();
}
/*========================================================================
功能: 添加菜单项
-------------------------------------------
uID: 菜单ID
strText: 菜单文本
nlevel: 菜单级别,请参考相关函数
==========================================================================*/
void CCoolMenu::AppendMenu(UINT uFlags, UINT uNewMenuItemID, CString strNewMenuItem, int nlevel)
{
LPCOOLMENU lpMenu = new COOLMENU;
lpMenu->nMenuID = uNewMenuItemID;
lpMenu->strText = strNewMenuItem;
lpMenu->nMenuLevel = nlevel;
CMenu::AppendMenu(MF_BYPOSITION | MF_OWNERDRAW | uFlags, lpMenu->nMenuID, LPCTSTR(lpMenu));
m_obMenuList.AddTail((CObject *)lpMenu);
}
/*========================================================================
功能: 子类化指定窗口
==========================================================================*/
void CCoolMenu::SubClass(HWND hwnd)
{
m_MenuHook.HookWindow(hwnd);
}
/*########################################################################
-----------------------
绘制菜单
-----------------------
########################################################################*/
/*========================================================================
功能: 计算菜单大小
--------------------------------------------
lpMIS: LPMEASUREITEMSTRUCT结构体
==========================================================================*/
void CCoolMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{
LPCOOLMENU lpMenu = (LPCOOLMENU)(lpMIS->itemData);
//分隔条---------------------------------
if(lpMenu->nMenuID == 0)
{
lpMIS->itemHeight = 5;
lpMIS->itemWidth = 50;
return;
}
//非分隔条-------------------------------
lpMIS->itemWidth = 50; // default width
lpMIS->itemHeight = 19;
CString strText = lpMenu->strText + lpMenu->strKeyName;
int nLen = strText.GetLength();
if (nLen > 0)
{
//计算绘制菜单文本所需宽度-------------------
CFont fontMenu;
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
NONCLIENTMETRICS nm;
nm.cbSize = sizeof(NONCLIENTMETRICS);
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, nm.cbSize, &nm, 0));
lf = nm.lfMenuFont;
fontMenu.CreateFontIndirect(&lf);
CDC *pDC = AfxGetMainWnd()->GetDC();
CFont *old = pDC->SelectObject(&fontMenu);
CSize sz = pDC->GetTextExtent(lpMenu->strText);
pDC->SelectObject(&old);
AfxGetMainWnd()->ReleaseDC(pDC);
fontMenu.DeleteObject();
//调整有快捷键提示的菜单的宽度,使宽度适中-------------
if (lpMenu->strKeyName != "") sz.cx += (62 - (strText.GetLength() % 8) * (sz.cx/strText.GetLength()));
if(lpMenu->nMenuID == -2)
{
//顶级菜单宽度---------------------------
lpMIS->itemWidth = sz.cx - 6;
}
else if (lpMenu->nMenuLevel <= MDS_TOP_SUBMENU)
{
//主菜单项宽度---------------------------
lpMIS->itemWidth = sz.cx + m_szMenuLogo.cx + m_szMenuIcon.cx + MENU_SPACE * 5;
}
else
{
//普通菜单宽度---------------------------
lpMIS->itemWidth = sz.cx + m_szMenuIcon.cx + MENU_SPACE * 5;
}
}
}
/*========================================================================
功能: 获取菜单命令ID对应的图标序列号
----------------------------------------------
uID: 菜单命令ID
==========================================================================*/
int CCoolMenu::GetIndex(UINT uID)
{
for(int i = 0; i < m_uIDArray.GetSize(); i ++)
{
if(uID == m_uIDArray[i])
{
if (i >= m_iImageList.GetImageCount()) return -1;
return i;
}
}
return -1;
}
/*========================================================================
功能: 绘制菜单
------------------------------------------------
lpDIS: 自绘信息结构体
==========================================================================*/
void CCoolMenu::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
LPCOOLMENU lpMenu = (LPCOOLMENU)(lpDIS->itemData);
if(!AfxIsValidAddress(lpMenu, sizeof(COOLMENU))) return ;
CDC *pdc = CDC::FromHandle(lpDIS->hDC);
const CRect rect = lpDIS->rcItem;
//#ifdef _DEBUG
// CMemoryState oldmem,newmem,diff;
// oldmem.Checkpoint();
//#endif
//建立内存上下文---------------------------------------
CDC *pDC = new CDC();
//#ifdef _DEBUG
// newmem.Checkpoint();
// if(diff.Difference(oldmem,newmem))
// {
// ASSERT(0);
// }
//#endif
pDC->CreateCompatibleDC(pdc);
CBitmap *bitmap, *oldbitmap;
bitmap = new CBitmap;
bitmap->CreateCompatibleBitmap(pdc,rect.right, rect.bottom);//improtant
oldbitmap = pDC->SelectObject(bitmap);
//把菜单字体选入内存设备上下文-----------------------------
CFont fontMenu, *oldfont;
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
NONCLIENTMETRICS nm;
nm.cbSize = sizeof(NONCLIENTMETRICS);
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, nm.cbSize, &nm, 0));
lf = nm.lfMenuFont;
// lf.lfUnderline=true;
fontMenu.CreateFontIndirect(&lf);
oldfont = pDC->SelectObject(&fontMenu);
pDC->SetBkColor(m_crMenuColor);
pDC->SetBkMode(TRANSPARENT);
pDC->SelectStockObject(NULL_BRUSH);
//用位图填充菜单背景
// CRect rect2;
// rect2.left+=m_szMenuLogo.cx;
// DrawBackGroundBmp(pdc,rect2,true);
//当当前菜单为主菜单时,空出左边用于绘制LOGO图片----------
int nMenuLogoBarcx = 0; //左边LOGO栏宽度
if (lpMenu->nMenuLevel <= MDS_TOP_SUBMENU) nMenuLogoBarcx = m_szMenuLogo.cx;
//绘制LOGO图片----------------------------
if (nMenuLogoBarcx > 0 && (lpDIS->itemAction & ODA_DRAWENTIRE)
&& lpMenu->nMenuLevel != MDS_TOP_SUBMENU)
{
DrawLogoBar(pdc, CRect(0, 0, m_szMenuLogo.cx, rect.bottom));
}
//取得菜单状态----------------------------
BOOL bIsSelected = (lpDIS->itemState & ODS_SELECTED);
BOOL bIsChecked = (lpDIS->itemState & ODS_CHECKED);
BOOL bIsGrayed = (lpDIS->itemState & ODS_GRAYED);
BOOL bIsHotLight = (lpDIS->itemState & ODS_HOTLIGHT );
//擦除背景---------------------------------
CRect rc = rect;
rc.left += nMenuLogoBarcx;
if (lpMenu->nMenuID == -2)//顶级菜单-------
{
CBrush Brush(::GetSysColor(COLOR_3DFACE));//即是非弹出菜单
pDC->FillRect(rc, &Brush);
}
else//非顶级菜单---------------------------
{
CBrush Brush(m_crMenuColor);
pDC->FillRect(rc, &Brush);
}
//绘制Office XP风格的图标栏灰色背景------------
if (lpMenu->nMenuID != -2 && (GetStyle() & CMS_ICONBAR != 0) && nMenuLogoBarcx == 0)
{
rc.right = rc.left + m_szMenuIcon.cx + MENU_SPACE*2 - 1;
pDC->FillSolidRect(rc,m_crIconBarColor);
}
//绘制分隔条-----------------------------------
if(lpMenu->nMenuID == 0)
{
rc = rect;
rc.top += rect.Height()/2; //居矩形区域中间
rc.bottom = rc.top + 2; //高两个象素
rc.left += (nMenuLogoBarcx + MENU_SPACE); //空出左边LOGO栏区
if ((GetStyle() & CMS_ICONBAR != 0) && nMenuLogoBarcx == 0)
{
//在XP风格下空出左边图标栏区域----------
rc.left += (m_szMenuIcon.cx + MENU_SPACE);
}
pDC->Draw3dRect(rc, ::GetSysColor(COLOR_GRAYTEXT), RGB(240, 240, 240));
}
else
{
//显示菜单文字-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//禁止菜单========================================================
if(bIsGrayed)
{
rc = rect;
rc.left += nMenuLogoBarcx; //空出左边LOGO栏区域
// 菜单被选择----------------------------------
if(bIsSelected)
{
// DrawLightBar(pDC, rc, FALSE);
}
//菜单文本----------------------------
if(lpMenu->strText.GetLength() > 0)
{
rc.left += (m_szMenuIcon.cx + MENU_SPACE*3 + 1);
rc.top += 2;
rc.right -= 11;//调节快捷方式的宽度"ctrl+o"
//绘制立体字---------------------------
pDC->SetTextColor(::GetSysColor(COLOR_3DLIGHT));
pDC->DrawText(lpMenu->strText, &rc, DT_EXPANDTABS | DT_VCENTER | DT_SINGLELINE);
pDC->DrawText(lpMenu->strKeyName, &rc, DT_EXPANDTABS | DT_VCENTER | DT_SINGLELINE | DT_RIGHT);
pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
rc.InflateRect(1,1,-1,-1);
pDC->DrawText(lpMenu->strText, &rc, DT_EXPANDTABS | DT_VCENTER | DT_SINGLELINE);
pDC->DrawText(lpMenu->strKeyName, &rc, DT_EXPANDTABS | DT_VCENTER | DT_SINGLELINE | DT_RIGHT);
}
}
//非禁止菜单==========================================================
else
{
//顶层菜单------------------------------------------
if (lpMenu->nMenuID == -2)
{
rc = rect;
rc.right -= 4;
m_rcMenuItem = rect;
//选择状态----------------------------
if (bIsSelected)
{
DrawMenuBar(pDC, rect);
pDC->SetTextColor(::GetSysColor(COLOR_MENUTEXT));
m_rcMenuItem = rect;
CRect rcFram;
AfxGetMainWnd()->GetWindowRect(&rcFram);
m_rcMenuItem.OffsetRect(rcFram.TopLeft());
}
//焦点状态----------------------------
else if (bIsHotLight)
{
DrawLightBar(pDC, rc);
pDC->SetTextColor(m_crHighLightColor);
m_rcMenuItem.SetRectEmpty();
}
//正常状态----------------------------
else
{
pDC->SetTextColor(::GetSysColor(COLOR_MENUTEXT));
m_rcMenuItem.SetRectEmpty();
}
//菜单文本----------------------------
if(lpMenu->strText.GetLength() > 0)
{
pDC->DrawText(lpMenu->strText, &rc, DT_EXPANDTABS | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
}
//非顶层菜单,是弹出菜单或者一个菜单项目---------------
else
{
rc = rect;
rc.left += nMenuLogoBarcx;
//选择状态-----------------------------
if(bIsSelected)
{
DrawLightBar(pDC, rc);
pDC->SetTextColor(m_crHighLightColor);
}
//非选择状态---------------------------
else
{
pDC->SetTextColor(m_crTextColor);
}
//菜单文本----------------------------
if(lpMenu->strText.GetLength() > 0)
{
rc.left += (m_szMenuIcon.cx + MENU_SPACE*3);
rc.right -= 12;
pDC->DrawText(lpMenu->strText, &rc, DT_EXPANDTABS |
DT_VCENTER | DT_SINGLELINE);
pDC->DrawText(lpMenu->strKeyName, &rc, DT_EXPANDTABS |
DT_VCENTER | DT_SINGLELINE | DT_RIGHT);
}
}
}
//<<绘制图标或Check标志-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
rc = rect;
rc.left += (nMenuLogoBarcx + MENU_SPACE -1);
rc.top += ((rect.Height() - m_szMenuIcon.cy)/2 + 1);
rc.right = rc.left + m_szMenuIcon.cx;
rc.bottom = rc.top + m_szMenuIcon.cy;
int nIndex = GetIndex(lpMenu->nMenuID);
//如果有图标------------------------------------------
if(nIndex >= 0)
{
//画图标Check框-----------------------------------
if(bIsChecked)
{
CRect rcc = rect;
rcc.left += nMenuLogoBarcx;
rcc.right = rcc.left + rect.Height() + 1;
if (bIsSelected)
{
// rcc.InflateRect(-1,-1);
// pDC->FillSolidRect(rcc,m_crMenuColor);
// pDC->Draw3dRect(rcc, RGB(255,255,255), TOP_COLOR);
}
else
{
pDC->FillSolidRect(rcc,RGB(235,235,235));
pDC->Draw3dRect(rc, RGB(160,170,210), RGB(160,170,210));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -