设置菜单条及菜单项背景色(转)

1、设置菜单条背景色

 

  1. // 菜单栏  
  2. m_wndMenu.LoadMenu(IDR_MAINFRAME);  
  3. SetMenu(&m_wndMenu);  
  4. // 改变菜单条背景颜色  
  5. MENUINFO   menuinfo;     
  6. menuinfo.cbSize = sizeof(MENUINFO);  
  7. menuinfo.fMask = MIM_BACKGROUND;     
  8. menuinfo.hbrBack = ::CreateSolidBrush(RGB(203, 228, 253));     
  9. CMenu*  pMenu = GetMenu();     
  10. ::SetMenuInfo(pMenu->m_hMenu, &menuinfo);     
  11. DrawMenuBar();  

2、设置菜单项背景色

重载CMenu类,重写DrawItem()方法。

网上有一个CMenuEx类,只要设置m_colMenu属性就可以了。该类可以实现Windows开始菜单风格,即菜单项可带有图标。

CMenuEx.h

#if !defined(AFX_MENUEX_H__FE677F6B_2315_11D7_8869_BB2B2A4F4D45__INCLUDED_)
#define AFX_MENUEX_H__FE677F6B_2315_11D7_8869_BB2B2A4F4D45__INCLUDED_
#include
"afxtempl.h"
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

typedef
struct tagMENUITEM
{
CString strText;
UINT uID;
#ifdef MENUCHAR
UINT uChr;
#endif
UINT uIndex;
int uPositionImageLeft;
}MENUITEM;
typedef MENUITEM
* LPMENUITEM;
///////////////////////////////////////////
class CMenuEx : public CMenu
{
public:
void InitPopupMenu(CMenu *pPopupMenu,UINT uToolBar,CToolBar *pToolBar);
void ChangeStyle(CMenu *pMenu,CToolBar *pToolBar,BOOL bIsMainMenu=FALSE);
void SetHighLightColor(COLORREF crColor);
void SetBackColor(COLORREF);
void SetTextColor(COLORREF);
#ifdef MENUCHAR
LRESULT MenuChar(UINT nChar);
#endif
void SetImageLeft(UINT idBmpLeft);
void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
void InitMenu(CMenu *pMenu,UINT uToolBar,CToolBar *pToolBar);
void DrawItem(LPDRAWITEMSTRUCT lpDIS);
CMenuEx();
virtual ~CMenuEx();

protected:
int m_nSeparator;
CSize m_szImageLeft;
CBitmap m_bmpImageLeft;
int m_nWidthLeftImage;
BOOL m_bHasImageLeft;
//是否有侧边位图
BOOL m_bInitial; //菜单是否已初始化,即设定了自绘风格
int GetImageFromToolBar(UINT uToolBar,CToolBar *pToolBar,COLORREF crMask=RGB(192,192,192));
CList m_ListMenu;

#ifdef MENUCHAR
CList m_currentListMenu;
//是m_ListMenu的子集,指当前打开的菜单
#endif

COLORREF m_colMenu;
COLORREF m_colTextSelected;
void DrawImageLeft(CDC *pDC,CRect &rect,LPMENUITEM lpItem);
void TextMenu(CDC *pDC,CRect &rect,CRect rtText,BOOL bSelected,BOOL bGrayed,LPMENUITEM lpItem);
CImageList m_ImageList;
COLORREF m_colText;
CSize m_szImage;
//菜单项位图的大小
void DrawMenuItemImage(CDC *pDC,CRect &rect,BOOL bSelected,BOOL bChecked,BOOL bGrayed,BOOL bHasImage,LPMENUITEM lpItem);
void GrayString(CDC *pDC,const CString &str,const CRect rect);
};

CMenuEx.cpp



 

 

#include "stdafx.h"    
#include "MenuEx.h"    
   
#ifdef _DEBUG    
#undef THIS_FILE    
static char THIS_FILE[]=__FILE__;   
#define new DEBUG_NEW    
#endif    
   
//////////////////////////////////////////////////////////////////////    
// Construction/Destruction    
//////////////////////////////////////////////////////////////////////    
   
CMenuEx::CMenuEx():m_szImage(16,15)   
{   
    m_colMenu =::GetSysColor(COLOR_MENU);   
    m_colText =::GetSysColor(COLOR_MENUTEXT);   
    m_colTextSelected =::GetSysColor(COLOR_HIGHLIGHTTEXT);   
   
    m_bInitial =FALSE;     
    m_bHasImageLeft =FALSE;   
    m_nSeparator = 10;  //sparator的默认高度    
}   
   
CMenuEx::~CMenuEx()   
{   
    m_ImageList.DeleteImageList();   
   
    while(!m_ListMenu.IsEmpty())   
        delete m_ListMenu.RemoveHead();   
   
    if(m_bHasImageLeft)   
        m_bmpImageLeft.DeleteObject();   
}   
/////////////////////////////////////////////////    
//当菜单项为不可用时绘制灰色的文本    
void CMenuEx::GrayString(CDC *pDC, const CString &str, const CRect rect)   
{   
    CRect   rt(rect);   
    //int nMode =pDC->SetBkMode(TRANSPARENT);    
   
    rt.left +=1;   
    rt.top +=1;   
           
    pDC->SetTextColor(RGB(255,255,255));   
    pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);   
   
    rt.left -=1;   
    rt.top -=1;   
    pDC->SetTextColor(RGB(127,127,127));   
    pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);   
   
    //pDC->SetBkMode(nMode);    
}   
/////////////////////////////////////////////////    
//绘制菜单项位图    
void CMenuEx::DrawMenuItemImage(CDC *pDC, CRect &rect, BOOL bSelected, BOOL bChecked,   
                                BOOL bGrayed, BOOL bHasImage,LPMENUITEM lpItem)   
{   
    CRect   rt(rect.left ,rect.top ,rect.left + m_szImage.cx + 4,   
                                    rect.top + m_szImage.cy + 4);   
   
    if(bChecked)   
    {      
        if(bGrayed)   
        {      
            //菜单不可用    
            GrayString(pDC,"√",rt);   
        }   
        else   
        {   
            if(bSelected)   
            {   
                //菜单选中    
                //当该项被选中仅多绘制一个立体矩形    
                pDC->Draw3dRect(&rt,RGB(255,255,255),RGB(127,127,127));   
            }   
   
            rt.InflateRect(-2,-2);   
               
            //画出"√"    
            pDC->SetBkMode(TRANSPARENT);   
            pDC->SetTextColor(m_colText);   
            pDC->DrawText("√",&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);   
        }   
           
        rect.left +=m_szImage.cx + 4 +2 ;   
           
        return ;   
    }   
       
   
    if(bHasImage)   
    {   
        CPoint pt(rt.left+2 , rt.top+2 );   
        UINT    uStyle =ILD_TRANSPARENT;    //CImageList::Draw()绘制位图的风格    
        if(bGrayed)   
        {   
            uStyle |=ILD_BLEND50;   //菜单不可用所以位图较暗    
        }   
        else   
        {   
            if(bSelected)   
            {   
                //当该项被选中仅多绘制一个立体矩形    
                pDC->Draw3dRect(&rt,RGB(255,255,255),RGB(127,127,127));   
            }   
        }   
   
        m_ImageList.Draw(pDC,lpItem->uIndex,pt,uStyle);  //在菜单项中绘制位图    
   
        //调整可绘制矩形的大小    
        //4:位图外接矩形比位图大4    
        //2:菜单文本与位图外接矩形的间隔为2    
        rect.left  +=m_szImage.cx + 4 + 2;   
    }   
}   
/////////////////////////////////////////////////    
//绘制菜单项文本    
//参数:rect:立体矩形的RECT    
//      rtText:菜单文本的RECT    
void CMenuEx::TextMenu(CDC *pDC, CRect &rect,CRect rtText,BOOL bSelected, BOOL bGrayed, LPMENUITEM lpItem)   
{   
    //选中状态的菜单项要先画出立体矩形    
    if(bSelected)   
        pDC->Draw3dRect(&rect,RGB(127,127,127),RGB(255,255,255));       
   
    if(bGrayed)   
    {   
        GrayString(pDC,lpItem->strText,rtText);   
    }   
    else   
    {   
        pDC->DrawText(lpItem->strText,rtText,DT_LEFT|DT_EXPANDTABS|DT_VCENTER);   
    }   
}   
   
void CMenuEx::DrawImageLeft(CDC *pDC, CRect &rect,LPMENUITEM lpItem)   
{   
    if(!m_bHasImageLeft || lpItem->uPositionImageLeft ==-1)   
        return ;   
       
    CDC  memDC;   
    memDC.CreateCompatibleDC(pDC);   
    CBitmap *oldBmp =(CBitmap *) memDC.SelectObject(&m_bmpImageLeft);   
   
    int cy; //设定该菜单项应从哪画起    
   
    if(m_szImageLeft.cy >= lpItem->uPositionImageLeft + rect.Height())   
    {   
        cy =(int) m_szImageLeft.cy - lpItem->uPositionImageLeft - rect.Height();   
        ASSERT(cy>=0);   
    }   
    else   
        cy =0;   
   
    pDC->BitBlt(rect.left ,rect.top ,m_szImageLeft.cx ,rect.Height(),&memDC,0,cy,SRCCOPY);   
   
    memDC.SelectObject(oldBmp);   
    memDC.DeleteDC();   
   
    rect.left +=m_szImageLeft.cx+1;   
}   
   
void CMenuEx::DrawItem(LPDRAWITEMSTRUCT lpDIS)   
{   
    CDC dc;   
    LPMENUITEM lpItem;   
    CRect rect(lpDIS->rcItem);   
    dc.Attach(lpDIS->hDC);   
    lpItem =(LPMENUITEM)lpDIS->itemData;   
   
    if(lpDIS->itemState & ODS_SELECTED)   
        dc.SetTextColor(m_colTextSelected);   
    else   
        dc.SetTextColor(m_colText);   
   
    //设定背景色    
    CBrush brush(m_colMenu);   
    dc.FillRect(&rect, &brush);   
       
    //设定显示模式    
    dc.SetBkMode(TRANSPARENT);   
   
    //绘制侧边位图    
    DrawImageLeft(&dc,rect,lpItem);   
   
    if(lpItem->uID==0)//分隔条    
    {   
        rect.top =rect.Height()/2+rect.top ;   
        rect.bottom =rect.top +2;   
        rect.left +=2;   
        rect.right -=2;   
   
        dc.Draw3dRect(rect,RGB(64,0,128),RGB(255,255,255));   
    }   
    else   
    {   
   
        BOOL    bSelected =lpDIS->itemState & ODS_SELECTED;   
        BOOL    bChecked  =lpDIS->itemState & ODS_CHECKED;   
        BOOL    bGrayed   =lpDIS->itemState & ODS_GRAYED;   
        BOOL    bHasImage =(lpItem->uIndex!=-1);   
   
        //设定菜单文本的区域    
        CRect   rtText(rect.left+m_szImage.cx+4+2, rect.top,rect.right ,rect.bottom );   
        rtText.InflateRect(-2,-2);   
                          
        //绘制菜单位图    
        DrawMenuItemImage(&dc,rect,bSelected,bChecked,bGrayed,bHasImage,lpItem);   
   
        //绘制菜单文本    
        TextMenu(&dc,rect,rtText,bSelected,bGrayed,lpItem);   
   
#ifdef MENUCHAR    
        //加入当前菜单链表    
        m_currentListMenu.AddTail(lpItem);   
#endif    
    }   
   
    dc.Detach();   
}   
//////////////////////////////////////////////////////////    
//改变菜单风格    
//注意第二个参数:FALSE:表示pMenu指向的不是第一级菜单    
void CMenuEx::ChangeStyle(CMenu *pMenu,CToolBar *pToolBar,BOOL bIsMainMenu)   
{   
    ASSERT(pMenu);   
    TRACE("ChangeStyle\n");//AfxMessageBox("");    
    LPMENUITEM  lpItem;   
    CMenu       *pSubMenu;   
    int         m,nPosition=0;  //该变量用来绘制侧边位图的位置    
    int inx;   
    UINT    idx,x;   
   
    for(int i=(int)pMenu->GetMenuItemCount()-1 ;i>=0; i--)   
    {   
        lpItem =new MENUITEM;   
   
        lpItem->uID =pMenu->GetMenuItemID(i);   
        if(!bIsMainMenu)    //不是第一级菜单    
            lpItem->uPositionImageLeft =-1;//二级以下菜单不支持侧边位图    
        else   
            lpItem->uPositionImageLeft =nPosition;   
   
        if(lpItem->uID >0)   
        {   
            if(bIsMainMenu)   
                nPosition +=m_szImage.cy+4;   
   
            //保存菜单文本    
            pMenu->GetMenuString(i,lpItem->strText,MF_BYPOSITION);   
   
#ifdef MENUCHAR    
            //保存菜单文本中&后的字符    
            //如果没有则lpItem->uChr为0    
            int ret=lpItem->strText.Find('&');   
            lpItem->uChr =0;   
            if(ret>=0)   
                lpItem->uChr =lpItem->strText[ret+1];   
            //字符统一成大小    
            lpItem->uChr &=~0x20;   
#endif    
               
            //由工具栏位图中寻找菜单项的位图    
            //如果没有则uIndex为-1    
            lpItem->uIndex =-1;   
            if(pToolBar)   
            {   
                for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++)   
                {   
                    pToolBar->GetButtonInfo(m,idx,x,inx);   
   
                    if(idx==lpItem->uID)   
                    {   
                        lpItem->uIndex=inx;   
                        break;   
                    }   
                }   
            }   
   
            //如果该项下还有子菜单,则递归调用该函数来修改其子菜单的风格    
            pSubMenu =pMenu->GetSubMenu(i);   
            if(pSubMenu)   
                ChangeStyle(pSubMenu,pToolBar);   
               
        }   
        else   
        {   
            if(bIsMainMenu)   
                nPosition +=m_nSeparator;   
        }   
        //修改菜单风格为自绘    
        pMenu->ModifyMenu(i,MF_BYPOSITION|MF_OWNERDRAW,lpItem->uID,(LPCTSTR)lpItem);   
           
        m_ListMenu.AddTail(lpItem);   
    }   
}   
//////////////////////////////////////////////////////////    
//由工具栏的位图来产生菜单所用的位图列表m_ImageList    
int CMenuEx::GetImageFromToolBar(UINT uToolBar, CToolBar *pToolBar,COLORREF crMask/*工具栏位图的掩码*/)   
{   
    if(!pToolBar)   
        return 0;   
   
    CBitmap bmp;   
    int nWidth,nHeight;   
    BITMAP  bmpInfo;   
   
    bmp.LoadBitmap(uToolBar);   
    bmp.GetBitmap(&bmpInfo);   
    //得到位图的高度    
    nHeight =bmpInfo.bmHeight;   
   
    int nCount=0;   
    int ret =pToolBar->GetToolBarCtrl().GetButtonCount();   
   
    //得到工具栏中位图的个数nCount    
    for(int i=0;i<RET;I++) if(pToolBar->GetItemID(i)!=ID_SEPARATOR)   
            nCount ++;   
       
    //计算出位图的宽度    
    nWidth =bmpInfo.bmWidth/nCount;   
   
    bmp.DeleteObject();   
   
    TRACE("Menu Bitmap--%d\theight:%d\n",nWidth,nHeight);   
       
    //创建位图列表    
    m_ImageList.Create(uToolBar,nWidth,nHeight,crMask);   
    m_szImage.cx =nWidth;   
    m_szImage.cy =nHeight;   
   
    return nCount;   
}   
   
void CMenuEx::InitMenu(CMenu *pMenu, UINT uToolBar, CToolBar *pToolBar)   
{   
    //已设定了风格    
    if(m_bInitial)   
        return ;   
   
    GetImageFromToolBar(uToolBar,pToolBar);   
   
    CMenu   *pSubMenu,*pSubsub;   
    MENUITEM    *lpItem;   
   
    UINT    i;   
    int     j,m;   
    int     nPosition;  //该变量用来绘制侧边位图的位置    
   
    for(i=0;i<PMENU->GetMenuItemCount();i++)   
    {   
        pSubMenu =pMenu->GetSubMenu(i);   
   
        if(pSubMenu)   
        {   
            nPosition =0;   
               
            //注意j一定要为int类型,如果为UINT是检查不出j>=0!    
            for(j=(int)pSubMenu->GetMenuItemCount()-1;j>=0;j--)   
            {   
                lpItem =new MENUITEM;          
   
                lpItem->uID =pSubMenu->GetMenuItemID(j);   
                lpItem->uPositionImageLeft =nPosition;   
   
                if(lpItem->uID>0)   
                {   
                    nPosition +=m_szImage.cy+4;   
   
                    pSubMenu->GetMenuString(j,lpItem->strText,MF_BYPOSITION);   
#ifdef MENUCHAR    
                    //保存菜单文本中&后的字符    
                    //如果没有则lpItem->uChr为0    
                    int ret =lpItem->strText.Find('&');   
                    lpItem->uChr=0;   
   
                    if(ret>=0)   
                        lpItem->uChr =lpItem->strText[ret+1];   
                    //统一大小    
                    lpItem->uChr &=~0x20;   
#endif    
                    //由工具栏位图中寻找菜单项的位图    
                    //如果没有则uIndex为-1    
                    lpItem->uIndex =-1;   
                    for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++)   
                    {   
                        int inx;   
                        UINT    idx,x;   
                        pToolBar->GetButtonInfo(m,idx,x,inx);   
   
                        if(idx==lpItem->uID)   
                        {   
                            lpItem->uIndex=inx;   
                            break;   
                        }   
                    }   
   
                }   
                else   
                {   
                    //separator    
                    nPosition +=m_nSeparator;   
                }   
               
                m_ListMenu.AddTail(lpItem);   
   
                pSubMenu->ModifyMenu(j,MF_BYPOSITION|MF_OWNERDRAW,   
                        lpItem->uID,LPCTSTR(lpItem));   
   
                pSubsub =pSubMenu->GetSubMenu(j);   
   
                //只有第一级菜单才由工具栏获得位图!!    
                if(pSubsub)   
                    ChangeStyle(pSubsub,pToolBar);   
            }   
        }   
    }   
   
    m_bInitial =TRUE;   
}   
   
void CMenuEx::MeasureItem(LPMEASUREITEMSTRUCT  lpMIS)   
{   
    MENUITEM *lpItem =(LPMENUITEM)lpMIS->itemData;   
   
    if(lpItem->uID==0)//分隔条    
    {   
        lpMIS->itemHeight =m_nSeparator;   
        //lpMIS->itemWidth  =50;    
    }   
    else   
    {   
        CDC  *pDC =AfxGetMainWnd()->GetDC();   
   
        CString strText=lpItem->strText;   
        CSize  size;   
   
        size=pDC->GetTextExtent(lpItem->strText);   
   
        lpMIS->itemWidth = size.cx +m_szImage.cx+4;   
           
        lpMIS->itemHeight =m_szImage.cy+4;   
           
        AfxGetMainWnd()->ReleaseDC(pDC);   
    }   
}   
   
void CMenuEx::SetImageLeft(UINT idBmpLeft)   
{   
    m_bmpImageLeft.LoadBitmap(idBmpLeft);   
    m_bHasImageLeft = TRUE;   
    BITMAP  bmpInfo;   
    m_bmpImageLeft.GetBitmap(&bmpInfo);   
   
    m_szImageLeft.cx =bmpInfo.bmWidth;   
    m_szImageLeft.cy =bmpInfo.bmHeight;   
}   
   
#ifdef MENUCHAR    
LRESULT CMenuEx::MenuChar(UINT nChar)   
{   
    nChar &=~0x20;   
    MENUITEM *lpItem;   
   
    for(POSITION pos=m_currentListMenu.GetHeadPosition();pos;)   
    {   
        lpItem =(LPMENUITEM)m_currentListMenu.GetNext(pos);   
   
        if(lpItem->uChr ==nChar)   
        {   
            AfxGetMainWnd()->SendMessage(WM_COMMAND,lpItem->uID);   
            return 1L;   
        }   
    }   
    return 0L;   
}   
#endif    
   
void CMenuEx::SetTextColor(COLORREF crColor)   
{   
    m_colText =crColor;   
}   
   
void CMenuEx::SetBackColor(COLORREF crColor)   
{   
    m_colMenu =crColor;   
}   
   
void CMenuEx::SetHighLightColor(COLORREF crColor)   
{   
    m_colTextSelected =crColor;   
}   
   
//////////////////////////////////////////////////////    
//修改菜单的风格    
//与InitMenu不同的是:InitMenu并不修改第一级菜单为自绘风格,而    
//该函数有包括第一级菜单    
//但必须注意:该类的任一实例都只能调用这两个函数中的一个,不能一同使用    
void CMenuEx::InitPopupMenu(CMenu *pPopupMenu,UINT uToolBar, CToolBar *pToolBar)   
{   
    //已设定了主窗口菜单风格    
    if(m_bInitial)   
        return ;   
   
    GetImageFromToolBar(uToolBar,pToolBar);   
   
    ChangeStyle(pPopupMenu,pToolBar);   
   
    m_bInitial =TRUE;   
}   
// MenuEx.cpp: implementation of the CMenuEx class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "MenuEx.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CMenuEx::CMenuEx():m_szImage(16,15) 
{ 
	m_colMenu =::GetSysColor(COLOR_MENU); 
	m_colText =::GetSysColor(COLOR_MENUTEXT); 
	m_colTextSelected =::GetSysColor(COLOR_HIGHLIGHTTEXT); 
 
	m_bInitial =FALSE;	 
	m_bHasImageLeft =FALSE; 
	m_nSeparator = 10;	//sparator的默认高度 
} 
 
CMenuEx::~CMenuEx() 
{ 
	m_ImageList.DeleteImageList(); 
 
	while(!m_ListMenu.IsEmpty()) 
		delete m_ListMenu.RemoveHead(); 
 
	if(m_bHasImageLeft) 
		m_bmpImageLeft.DeleteObject(); 
} 
///////////////////////////////////////////////// 
//当菜单项为不可用时绘制灰色的文本 
void CMenuEx::GrayString(CDC *pDC, const CString &str, const CRect rect) 
{ 
	CRect	rt(rect); 
	//int nMode =pDC->SetBkMode(TRANSPARENT); 
 
	rt.left +=1; 
	rt.top +=1; 
		 
	pDC->SetTextColor(RGB(255,255,255)); 
	pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE); 
 
	rt.left -=1; 
	rt.top -=1; 
	pDC->SetTextColor(RGB(127,127,127)); 
	pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE); 
 
	//pDC->SetBkMode(nMode); 
} 
///////////////////////////////////////////////// 
//绘制菜单项位图 
void CMenuEx::DrawMenuItemImage(CDC *pDC, CRect &rect, BOOL bSelected, BOOL bChecked, 
								BOOL bGrayed, BOOL bHasImage,LPMENUITEM lpItem) 
{ 
	CRect	rt(rect.left ,rect.top ,rect.left + m_szImage.cx + 4, 
									rect.top + m_szImage.cy + 4); 
 
	if(bChecked) 
	{	 
		if(bGrayed) 
		{	 
			//菜单不可用 
			GrayString(pDC,"√",rt); 
		} 
		else 
		{ 
			if(bSelected) 
			{ 
				//菜单选中 
				//当该项被选中仅多绘制一个立体矩形 
				pDC->Draw3dRect(&rt,RGB(255,255,255),RGB(127,127,127)); 
			} 
 
			rt.InflateRect(-2,-2); 
			 
			//画出"√" 
			pDC->SetBkMode(TRANSPARENT); 
			pDC->SetTextColor(m_colText); 
			pDC->DrawText("√",&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE); 
		} 
		 
		rect.left +=m_szImage.cx + 4 +2 ; 
		 
		return ; 
	} 
	 
 
	if(bHasImage) 
	{ 
		CPoint pt(rt.left+2 , rt.top+2 ); 
		UINT	uStyle =ILD_TRANSPARENT;	//CImageList::Draw()绘制位图的风格 
		if(bGrayed) 
		{ 
			uStyle |=ILD_BLEND50;	//菜单不可用所以位图较暗 
		} 
		else 
		{ 
			if(bSelected) 
			{ 
				//当该项被选中仅多绘制一个立体矩形 
				pDC->Draw3dRect(&rt,RGB(255,255,255),RGB(127,127,127)); 
			} 
		} 
 
		m_ImageList.Draw(pDC,lpItem->uIndex,pt,uStyle);	//在菜单项中绘制位图 
 
		//调整可绘制矩形的大小 
		//4:位图外接矩形比位图大4 
		//2:菜单文本与位图外接矩形的间隔为2 
		rect.left  +=m_szImage.cx + 4 + 2; 
	} 
} 
///////////////////////////////////////////////// 
//绘制菜单项文本 
//参数:rect:立体矩形的RECT 
//		rtText:菜单文本的RECT 
void CMenuEx::TextMenu(CDC *pDC, CRect &rect,CRect rtText,BOOL bSelected, BOOL bGrayed, LPMENUITEM lpItem) 
{ 
	//选中状态的菜单项要先画出立体矩形 
	if(bSelected) 
		pDC->Draw3dRect(&rect,RGB(127,127,127),RGB(255,255,255));	 
 
	if(bGrayed) 
	{ 
		GrayString(pDC,lpItem->strText,rtText); 
	} 
	else 
	{ 
		pDC->DrawText(lpItem->strText,rtText,DT_LEFT|DT_EXPANDTABS|DT_VCENTER); 
	} 
} 
 
void CMenuEx::DrawImageLeft(CDC *pDC, CRect &rect,LPMENUITEM lpItem) 
{ 
	if(!m_bHasImageLeft || lpItem->uPositionImageLeft ==-1) 
		return ; 
	 
	CDC  memDC; 
	memDC.CreateCompatibleDC(pDC); 
	CBitmap	*oldBmp =(CBitmap *) memDC.SelectObject(&m_bmpImageLeft); 
 
	int cy;	//设定该菜单项应从哪画起 
 
	if(m_szImageLeft.cy >= lpItem->uPositionImageLeft + rect.Height()) 
	{ 
		cy =(int) m_szImageLeft.cy - lpItem->uPositionImageLeft - rect.Height(); 
		ASSERT(cy>=0); 
	} 
	else 
		cy =0; 
 
	pDC->BitBlt(rect.left ,rect.top ,m_szImageLeft.cx ,rect.Height(),&memDC,0,cy,SRCCOPY); 
 
	memDC.SelectObject(oldBmp); 
	memDC.DeleteDC(); 
 
	rect.left +=m_szImageLeft.cx+1; 
} 
 
void CMenuEx::DrawItem(LPDRAWITEMSTRUCT lpDIS) 
{ 
	CDC	dc; 
	LPMENUITEM lpItem; 
	CRect rect(lpDIS->rcItem); 
	dc.Attach(lpDIS->hDC); 
	lpItem =(LPMENUITEM)lpDIS->itemData; 
 
	if(lpDIS->itemState & ODS_SELECTED) 
		dc.SetTextColor(m_colTextSelected); 
	else 
		dc.SetTextColor(m_colText); 
 
	//设定背景色 
	CBrush brush(m_colMenu); 
	dc.FillRect(&rect, &brush); 
	 
	//设定显示模式 
	dc.SetBkMode(TRANSPARENT); 
 
	//绘制侧边位图 
	DrawImageLeft(&dc,rect,lpItem); 
 
	if(lpItem->uID==0)//分隔条 
	{ 
		rect.top =rect.Height()/2+rect.top ; 
		rect.bottom =rect.top +2; 
		rect.left +=2; 
		rect.right -=2; 
 
		dc.Draw3dRect(rect,RGB(64,0,128),RGB(255,255,255)); 
	} 
	else 
	{ 
 
		BOOL	bSelected =lpDIS->itemState & ODS_SELECTED; 
		BOOL	bChecked  =lpDIS->itemState & ODS_CHECKED; 
		BOOL	bGrayed	  =lpDIS->itemState & ODS_GRAYED; 
		BOOL	bHasImage =(lpItem->uIndex!=-1); 
 
		//设定菜单文本的区域 
		CRect	rtText(rect.left+m_szImage.cx+4+2, rect.top,rect.right ,rect.bottom ); 
		rtText.InflateRect(-2,-2); 
					    
		//绘制菜单位图 
		DrawMenuItemImage(&dc,rect,bSelected,bChecked,bGrayed,bHasImage,lpItem); 
 
		//绘制菜单文本 
		TextMenu(&dc,rect,rtText,bSelected,bGrayed,lpItem); 
 
#ifdef MENUCHAR 
		//加入当前菜单链表 
		m_currentListMenu.AddTail(lpItem); 
#endif 
	} 
 
	dc.Detach(); 
} 
////////////////////////////////////////////////////////// 
//改变菜单风格 
//注意第二个参数:FALSE:表示pMenu指向的不是第一级菜单 
void CMenuEx::ChangeStyle(CMenu *pMenu,CToolBar *pToolBar,BOOL bIsMainMenu) 
{ 
	ASSERT(pMenu); 
	TRACE("ChangeStyle\n");//AfxMessageBox(""); 
	LPMENUITEM	lpItem; 
	CMenu		*pSubMenu; 
	int			m,nPosition=0;	//该变量用来绘制侧边位图的位置 
	int inx; 
	UINT	idx,x; 
 
	for(int i=(int)pMenu->GetMenuItemCount()-1 ;i>=0; i--) 
	{ 
		lpItem =new MENUITEM; 
 
		lpItem->uID =pMenu->GetMenuItemID(i); 
		if(!bIsMainMenu)	//不是第一级菜单 
			lpItem->uPositionImageLeft =-1;//二级以下菜单不支持侧边位图 
		else 
			lpItem->uPositionImageLeft =nPosition; 
 
		if(lpItem->uID >0) 
		{ 
			if(bIsMainMenu) 
				nPosition +=m_szImage.cy+4; 
 
			//保存菜单文本 
			pMenu->GetMenuString(i,lpItem->strText,MF_BYPOSITION); 
 
#ifdef MENUCHAR 
			//保存菜单文本中&后的字符 
			//如果没有则lpItem->uChr为0 
			int ret=lpItem->strText.Find('&'); 
			lpItem->uChr =0; 
			if(ret>=0) 
				lpItem->uChr =lpItem->strText[ret+1]; 
			//字符统一成大小 
			lpItem->uChr &=~0x20; 
#endif 
			 
			//由工具栏位图中寻找菜单项的位图 
			//如果没有则uIndex为-1 
			lpItem->uIndex =-1; 
			if(pToolBar) 
			{ 
				for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++) 
				{ 
					pToolBar->GetButtonInfo(m,idx,x,inx); 
 
					if(idx==lpItem->uID) 
					{ 
						lpItem->uIndex=inx; 
						break; 
					} 
				} 
			} 
 
			//如果该项下还有子菜单,则递归调用该函数来修改其子菜单的风格 
			pSubMenu =pMenu->GetSubMenu(i); 
			if(pSubMenu) 
				ChangeStyle(pSubMenu,pToolBar); 
			 
		} 
		else 
		{ 
			if(bIsMainMenu) 
				nPosition +=m_nSeparator; 
		} 
		//修改菜单风格为自绘 
		pMenu->ModifyMenu(i,MF_BYPOSITION|MF_OWNERDRAW,lpItem->uID,(LPCTSTR)lpItem); 
		 
		m_ListMenu.AddTail(lpItem); 
	} 
} 
////////////////////////////////////////////////////////// 
//由工具栏的位图来产生菜单所用的位图列表m_ImageList 
int CMenuEx::GetImageFromToolBar(UINT uToolBar, CToolBar *pToolBar,COLORREF	crMask/*工具栏位图的掩码*/) 
{ 
	if(!pToolBar) 
		return 0; 
 
	CBitmap	bmp; 
	int nWidth,nHeight; 
	BITMAP	bmpInfo; 
 
	bmp.LoadBitmap(uToolBar); 
	bmp.GetBitmap(&bmpInfo); 
	//得到位图的高度 
	nHeight =bmpInfo.bmHeight; 
 
	int nCount=0; 
	int	ret =pToolBar->GetToolBarCtrl().GetButtonCount(); 
 
	//得到工具栏中位图的个数nCount 
	for(int i=0;iGetItemID(i)!=ID_SEPARATOR) 
			nCount ++; 
	 
	//计算出位图的宽度 
	nWidth =bmpInfo.bmWidth/nCount; 
 
	bmp.DeleteObject(); 
 
	TRACE("Menu Bitmap--%d\theight:%d\n",nWidth,nHeight); 
	 
	//创建位图列表 
	m_ImageList.Create(uToolBar,nWidth,nHeight,crMask); 
	m_szImage.cx =nWidth; 
	m_szImage.cy =nHeight; 
 
	return nCount; 
} 
 
void CMenuEx::InitMenu(CMenu *pMenu, UINT uToolBar, CToolBar *pToolBar) 
{ 
	//已设定了风格 
	if(m_bInitial) 
		return ; 
 
	GetImageFromToolBar(uToolBar,pToolBar); 
 
	CMenu	*pSubMenu,*pSubsub; 
	MENUITEM	*lpItem; 
 
	UINT	i; 
	int		j,m; 
	int 	nPosition;	//该变量用来绘制侧边位图的位置 
 
	for(i=0;iGetMenuItemCount();i++) 
	{ 
		pSubMenu =pMenu->GetSubMenu(i); 
 
		if(pSubMenu) 
		{ 
			nPosition =0; 
			 
			//注意j一定要为int类型,如果为UINT是检查不出j>=0! 
			for(j=(int)pSubMenu->GetMenuItemCount()-1;j>=0;j--) 
			{ 
				lpItem =new MENUITEM;		 
 
				lpItem->uID =pSubMenu->GetMenuItemID(j); 
				lpItem->uPositionImageLeft =nPosition; 
 
				if(lpItem->uID>0) 
				{ 
					nPosition +=m_szImage.cy+4; 
 
					pSubMenu->GetMenuString(j,lpItem->strText,MF_BYPOSITION); 
#ifdef MENUCHAR 
					//保存菜单文本中&后的字符 
					//如果没有则lpItem->uChr为0 
					int ret =lpItem->strText.Find('&'); 
					lpItem->uChr=0; 
 
					if(ret>=0) 
						lpItem->uChr =lpItem->strText[ret+1]; 
					//统一大小 
					lpItem->uChr &=~0x20; 
#endif 
					//由工具栏位图中寻找菜单项的位图 
					//如果没有则uIndex为-1 
					lpItem->uIndex =-1; 
					for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++) 
					{ 
						int inx; 
						UINT	idx,x; 
						pToolBar->GetButtonInfo(m,idx,x,inx); 
 
						if(idx==lpItem->uID) 
						{ 
							lpItem->uIndex=inx; 
							break; 
						} 
					} 
 
				} 
				else 
				{ 
					//separator 
					nPosition +=m_nSeparator; 
				} 
			 
				m_ListMenu.AddTail(lpItem); 
 
				pSubMenu->ModifyMenu(j,MF_BYPOSITION|MF_OWNERDRAW, 
						lpItem->uID,LPCTSTR(lpItem)); 
 
				pSubsub =pSubMenu->GetSubMenu(j); 
 
				//只有第一级菜单才由工具栏获得位图!! 
				if(pSubsub) 
					ChangeStyle(pSubsub,pToolBar); 
			} 
		} 
	} 
 
	m_bInitial =TRUE; 
} 
 
void CMenuEx::MeasureItem(LPMEASUREITEMSTRUCT  lpMIS) 
{ 
	MENUITEM *lpItem =(LPMENUITEM)lpMIS->itemData; 
 
	if(lpItem->uID==0)//分隔条 
	{ 
		lpMIS->itemHeight =m_nSeparator; 
		//lpMIS->itemWidth  =50; 
	} 
	else 
	{ 
		CDC	 *pDC =AfxGetMainWnd()->GetDC(); 
 
		CString	strText=lpItem->strText; 
		CSize  size; 
 
		size=pDC->GetTextExtent(lpItem->strText); 
 
		lpMIS->itemWidth = size.cx +m_szImage.cx+4; 
		 
		lpMIS->itemHeight =m_szImage.cy+4; 
		 
		AfxGetMainWnd()->ReleaseDC(pDC); 
	} 
} 
 
void CMenuEx::SetImageLeft(UINT idBmpLeft) 
{ 
	m_bmpImageLeft.LoadBitmap(idBmpLeft); 
	m_bHasImageLeft = TRUE; 
	BITMAP	bmpInfo; 
	m_bmpImageLeft.GetBitmap(&bmpInfo); 
 
	m_szImageLeft.cx =bmpInfo.bmWidth; 
	m_szImageLeft.cy =bmpInfo.bmHeight; 
} 
 
#ifdef MENUCHAR 
LRESULT CMenuEx::MenuChar(UINT nChar) 
{ 
	nChar &=~0x20; 
	MENUITEM *lpItem; 
 
	for(POSITION pos=m_currentListMenu.GetHeadPosition();pos;) 
	{ 
		lpItem =(LPMENUITEM)m_currentListMenu.GetNext(pos); 
 
		if(lpItem->uChr ==nChar) 
		{ 
			AfxGetMainWnd()->SendMessage(WM_COMMAND,lpItem->uID); 
			return 1L; 
		} 
	} 
	return 0L; 
} 
#endif 
 
void CMenuEx::SetTextColor(COLORREF crColor) 
{ 
	m_colText =crColor; 
} 
 
void CMenuEx::SetBackColor(COLORREF crColor) 
{ 
	m_colMenu =crColor; 
} 
 
void CMenuEx::SetHighLightColor(COLORREF crColor) 
{ 
	m_colTextSelected =crColor; 
} 
 
////////////////////////////////////////////////////// 
//修改菜单的风格 
//与InitMenu不同的是:InitMenu并不修改第一级菜单为自绘风格,而 
//该函数有包括第一级菜单 
//但必须注意:该类的任一实例都只能调用这两个函数中的一个,不能一同使用 
void CMenuEx::InitPopupMenu(CMenu *pPopupMenu,UINT uToolBar, CToolBar *pToolBar) 
{ 
	//已设定了主窗口菜单风格 
	if(m_bInitial) 
		return ; 
 
	GetImageFromToolBar(uToolBar,pToolBar); 
 
	ChangeStyle(pPopupMenu,pToolBar); 
 
	m_bInitial =TRUE; 
} 

原文地址:https://www.cnblogs.com/Daywei/p/1966891.html