CMenu的美化

来源:互联网 发布:java中thread类 编辑:程序博客网 时间:2024/06/05 09:21

菜单(menu)的美化:

1.先介绍一下使用MFC类库自带的CMFCPopupMenu类进行Menu的美化,下面代码实现了菜单背景色,选中的背景色,还有字体以及字的颜色等信息的设置,虽然字体大小的改变能够改变菜单每项的高度,但是并不能够随意调整菜单的高度。

CWinAppEx* pApp = DYNAMIC_DOWNCAST(CWinAppEx, AfxGetApp());if(NULL != pApp){CMFCPopupMenu* pMenu = pApp->GetContextMenuManager()->ShowPopupMenu(pPopup->GetSafeHmenu(), pt.x, pt.y, this, FALSE);COLORREF clrHilite = RGB(255,255,0);COLORREF clrBarFace = RGB(220, 220, 220);CBrush brHilite;::afxGlobalData.brHilite.DeleteObject();::afxGlobalData.brHilite.CreateSolidBrush(clrHilite);::afxGlobalData.brBarFace.DeleteObject();::afxGlobalData.brBarFace.CreateSolidBrush(clrBarFace);::afxGlobalData.fontRegular.DeleteObject();::afxGlobalData.fontRegular.CreateFont(13,                        // nHeight0,                         // nWidth0,                         // nEscapement0,                         // nOrientationFW_NORMAL,                 // nWeightFALSE,                     // bItalicFALSE,                     // bUnderline0,                         // cStrikeOutANSI_CHARSET,              // nCharSetOUT_DEFAULT_PRECIS,        // nOutPrecisionCLIP_DEFAULT_PRECIS,       // nClipPrecisionDEFAULT_QUALITY,           // nQualityDEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily_T("宋体"));  // lpszFacename;::afxGlobalData.clrTextHilite = RGB(255,0,0);//::afxGlobalData.clrWindowText = RGB(0,255,0);pMenu->SetMaxWidth(200);pMenu->SetAutoDestroy(TRUE);pMenu->SetForegroundWindow();}
2.使用CMFCPopupMenu类中的函数来进行menu的美化效果,不能达到自己预期的结果,顾继承CMenu,重绘一个新的Menu

    (1)首先我们继承MeasureItem函数,来设定菜单每项的高度与宽度

             

void CB2BMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct){lpMeasureItemStruct->itemHeight = m_itemH;lpMeasureItemStruct->itemWidth  = m_itemW;}
     (2)加入函数ChangeMenuItem,此函数的主要功能其实就是获取菜单项的ID和菜单项的内容

void CB2BMenu::ChangeMenuItem(CString *pText[]){int itemCount=this->GetMenuItemCount();//CString *pText[20];for(int i=0;i<itemCount;i++){UINT itemID=this->GetMenuItemID(i);//获取菜单项ID号pText[i] = new CString;if(NULL == pText[i])return;this->GetMenuString(i,*pText[i],MF_BYPOSITION);//获取菜单文本//ModifyMenu函数最后一个参数对应DRAWITEMSTRUCT结构里的itemData变量this->ModifyMenu(i,MF_OWNERDRAW|MF_BYPOSITION|MF_STRING|MF_CHECKED,itemID,(LPCTSTR)(*pText[i]));if(itemID == -1)//如果是一个弹出式菜单{CB2BMenu* pSubMenu = (CB2BMenu*)(this->GetSubMenu(i));if(NULL != pSubMenu){   pSubMenu->ChangeMenuItem(pText);}}}  }

此函数中的参数CString *pText[],虽然可以用局部指针变量CString *pText代替,但是存在内存泄露,如果你直接在此函数中释放此指针所指内存空间,则在下面Draw菜单时无法正确的显示出菜单内容,原因是因为DrawItem执行的时候是从刚才的内存空间中去取值,细节大家慢慢推敲。

(3)DrawItem的实现

void CB2BMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){CRect rect=lpDrawItemStruct->rcItem;CDC dc;dc.Attach(lpDrawItemStruct->hDC);CFont Font;Font.CreateFont(13,                        // nHeight0,                         // nWidth0,                         // nEscapement0,                         // nOrientationFW_NORMAL,                 // nWeightFALSE,                     // bItalicFALSE,                     // bUnderline0,                         // cStrikeOutANSI_CHARSET,              // nCharSetOUT_DEFAULT_PRECIS,        // nOutPrecisionCLIP_DEFAULT_PRECIS,       // nClipPrecisionDEFAULT_QUALITY,           // nQualityDEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily_T("宋体"));  // lpszFacename;dc.SelectObject(&Font);CString pText=(CString)(LPCTSTR)lpDrawItemStruct->itemData;CRect rcTemp,rcTemp1;rcTemp = rect;rcTemp1 = rect;if(lpDrawItemStruct->itemState&ODS_SELECTED){dc.FillSolidRect(rect,m_corSelMenu);//菜单被选中dc.SetTextColor(m_corSelText);//设置文本颜色rcTemp.left += 25;dc.DrawText(pText,rcTemp,DT_VCENTER|DT_LEFT|DT_SINGLELINE);}else{rcTemp.right = rcTemp.left + 22;dc.FillSolidRect(rect,m_corBkMenu);dc.SetTextColor(m_corText);//设置文本颜色rcTemp1.left += 25;dc.DrawText(pText,rcTemp1,DT_VCENTER|DT_LEFT|DT_SINGLELINE);dc.FillSolidRect(rcTemp,m_corLeftIconBk);}//根据菜单项ID来加载图标HICON hicon;if (lpDrawItemStruct->itemID == ID_MENU_TKTOUT){hicon = AfxGetApp()->LoadIcon(IDI_ICON1);DrawIconEx(dc,rect.left + 3, rect.top + 3,hicon,16,16,0,NULL,DI_NORMAL);}else if (lpDrawItemStruct->itemID == ID_MENU_PAY){hicon = AfxGetApp()->LoadIcon(IDI_ICON1);DrawIconEx(dc,rect.left + 3, rect.top + 3,hicon,16,16,0,NULL,DI_NORMAL);}dc.Detach();}
(4)下面为如何使用此类,其中m_menu为成员变量,类型为CB2BMenu,即自己写的Menu类:

m_menu.DestroyMenu();CPoint pt;GetCursorPos(&pt);SetForegroundWindow();m_menu.LoadMenu(IDR_CTXMENU);//BOOL ret = CMFCToolBar::AddToolBarForImageCollection(IDR_CTXMENU, IDR_CTXMENU);CB2BMenu* pPopup = (CB2BMenu*)m_menu.GetSubMenu(0);if (pPopup != NULL){pPopup->ChangeMenuItem(m_pStrText);pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, AfxGetMainWnd());}
代码中第四行SetForegroundWindow()是实现了点击除菜单的其他位置时,菜单消失的效果。

分别响应 ON_WM_MEASUREITEM()与ON_WM_DRAWITEM(),

void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct){// TODO: Add your message handler code here and/or call defaultif(lpMeasureItemStruct->CtlType == ODT_MENU){m_menu.MeasureItem(lpMeasureItemStruct);}else{CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);}}void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct){// TODO: Add your message handler code here and/or call defaultif(lpDrawItemStruct->CtlType == ODT_MENU){m_menu.DrawItem(lpDrawItemStruct);}else {CFrameWnd::OnDrawItem(nIDCtl, lpDrawItemStruct);}}