步骤如下:
(1)创建一个基于对话框的应用程序
(2)在工作区选择资源视图选项卡,右击节点,选择Insert命令,插入一个对话框资源
(3)打开类向导,创建一个新类,类名为CMenuIcon,打开CMenuIcon的头文件,为该类添加一个基类CMenu;
(4)在CMenuIcon头文件定义一个数据结构,用来保存菜单项信息
struct CMenuItem { CString m_ItemText; //菜单项文本 int m_IconIndex; //菜单项索引 int m_ItemID; //菜单标记,-1为顶层菜单,0为分割条,其他为普通菜单项 }; const int MAX_MENUCOUNT = 60,ITEMHEIGHT = 30,ITEMWIDTH= 80; //菜单项数量(图标数,高度,宽度增量)
CMenuItem m_ItemLists[MAX_MENUCOUNT]; //菜单项信息 int m_Index; //临时索引 int m_IconIndex; //菜单项图标索引 CImageList m_ImageList; //存储菜单项图标
CMenuIcon::CMenuIcon() { m_Index = 0; m_IconIndex = 0; m_ImageList.Create(26,26,ILC_COLOR32|ILC_MASK,0,0); //创建图像列表 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1)); //添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2)); //添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON3)); //添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON4)); //添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON5)); //添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON6)); //添加图标 }
BOOL CMenuIcon::AttatchMenu(UINT m_uID) { LoadMenu(m_uID); //加载菜单资源 return TRUE; }(8)在CMenuIcon类中添加MenuItem方法,该方法用来修改菜单项信息
// 该方法用于修改菜单项信息,使其包含MF_OWNERDRAW风格,并将菜单项信息存储在m_ItenLists成员变量中 BOOL CMenuIcon::MenuItem(CMenu* pMenu) { if (pMenu!=NULL) //判断菜单句柄是否为空 { int m_Count = pMenu->GetMenuItemCount(); //获得菜单数 for (int i = 0 ; i < m_Count ; i++) { //获得菜单文本 pMenu->GetMenuString(i,m_ItemLists[m_Index].m_ItemText,MF_BYPOSITION); int m_itemID = pMenu->GetMenuItemID(i); //获得菜单ID m_ItemLists[m_Index].m_ItemID = m_itemID; //将菜单ID保存在变量中 if (m_itemID > 0) { m_ItemLists[m_Index].m_IconIndex = m_IconIndex; //将图标索引值赋给变量 m_IconIndex++; //下一个图标索引 } //修改菜单信息 pMenu->ModifyMenu(i , MF_OWNERDRAW|MF_BYPOSITION|MF_STRING , m_ItemLists[m_Index].m_ItemID , (LPCTSTR)&(m_ItemLists[m_Index])); m_Index++; CMenu* m_SubMenu = pMenu->GetSubMenu(i); //获取弹出式菜单项 if (m_SubMenu) { MenuItem(m_SubMenu); //递归调用MenuItem方法 } } } return TRUE; }(9)重载CMenIcon类的MeasureItem虚拟方法,计算菜单项的大小
void CMenuIcon::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // TODO: 添加您的代码以确定指定项的大小 if (lpMeasureItemStruct->CtlType == ODT_MENU) //是否是自绘菜单 { lpMeasureItemStruct->itemHeight = ITEMHEIGHT; //菜单项高度 //lpMeasureItemStruct->itemWidth = ITEMWIDTH; //菜单项的宽度 CMenuItem* m_item; m_item = (CMenuItem*)lpMeasureItemStruct->itemData; //获得菜单项数据 //设置菜单项宽度 lpMeasureItemStruct->itemWidth = ((CMenuItem*)lpMeasureItemStruct->itemData)->m_ItemText.GetLength()*10+ITEMWIDTH; if (m_item->m_ItemID == 0) //判断是否为分割条 { lpMeasureItemStruct->itemHeight = 2; //将分割条的高度设为2 } } }
(10)在CMenuIcon类中添加DrawItemText成员,用于绘制菜单项文本
void CMenuIcon::DrawItemText(CDC* pDC, LPCTSTR Str, CRect Rect) { pDC->DrawText(Str,Rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE); //绘制菜单项文本 }
void CMenuIcon::DrawItemIcon(CDC* pDC, CRect Rect, int Icon) { m_ImageList.Draw(pDC,Icon,CPoint(Rect.left+2,Rect.top+4),ILD_TRANSPARENT); //绘制菜单项图标 }(12)在CMenuIcon类中添加DrawSeparater,用户绘制分割条
void CMenuIcon::DrawSeparater(CDC* pDC, CRect Rect) { pDC->Draw3dRect(Rect,RGB(255,0,255),RGB(255,0,255)); //使用紫色绘制分割条 }(13)在CMenuIcon类中添加DrawTopMenu,用于绘制顶层菜单
void CMenuIcon::DrawTopMenu(CDC* pDC, CRect Rect, bool Selected) { if (Selected) //判断菜单项是否选中 { pDC->Rectangle(&Rect); //绘制矩形区域 Rect.DeflateRect(1,1); //设置区域大小 pDC->FillSolidRect(Rect,RGB(190,170,220));//填充矩形区域 } else { pDC->FillSolidRect(&Rect,RGB(192,192,192)); //用另一种颜色填充矩形 } }(14)在CMenIcon类中添加DrawComMenu成员函数,绘制普通菜单项
void CMenuIcon::DrawComMenu(CDC* pDC, CRect Rect, bool Selected) { if (Selected) { pDC->Rectangle(Rect); //绘制矩形区域 Rect.DeflateRect(1,1); //设置区域大小 pDC->FillSolidRect(Rect,RGB(255,0,0));//填充矩形区域 } else { pDC->FillSolidRect(Rect,RGB(255,255,255)); //用另一种颜色填充矩形 } }
void CMenuIcon::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TODO: 添加您的代码以绘制指定项 if (lpDrawItemStruct->CtlType == ODT_MENU) //判断是否重绘菜单 { if (lpDrawItemStruct->itemData == NULL) { return; //如果数据为空则结束 } } unsigned int m_state = lpDrawItemStruct->itemState; //菜单项状态 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); //获得设备上下文DC CString str = ((CMenuItem*)(lpDrawItemStruct->itemData))->m_ItemText; //菜单项文本 LPCTSTR m_str = str.GetBuffer(str.GetLength()); //获得文本长度 int m_itemID = ((CMenuItem*)(lpDrawItemStruct->itemData))->m_ItemID; //获得菜单索引 int m_itemicon = ((CMenuItem*)(lpDrawItemStruct->itemData))->m_IconIndex; //获得图标索引 CRect m_rect = lpDrawItemStruct->rcItem; //获得菜单区域 pDC->SetBkMode(TRANSPARENT); //设置文本背景透明 switch (m_itemID) { case -1: //顶层菜单 //绘制顶层菜单 DrawTopMenu(pDC,m_rect,(m_state&ODS_SELECTED)||(m_state&0x0040)); DrawItemText(pDC,m_str,m_rect); //绘制菜单文本 break; case 0: DrawSeparater(pDC,m_rect); //绘制分割条 break; default: DrawComMenu(pDC,m_rect,m_state&ODS_SELECTED); //绘制菜单项 DrawItemText(pDC,m_str,m_rect); //绘制菜单文本 DrawItemIcon(pDC,m_rect,m_itemicon); //绘制菜单图标 break; } }(16)在对话框头文件中声明CMenuIcon类对象m_Menu;
(17)在对话框OnInitDialog方法中加载菜单资源,并设置菜单项
// TODO: 在此添加额外的初始化代码 m_Menu.AttatchMenu(IDR_MENU1); //加载菜单资源 m_Menu.MenuItem(&m_Menu); //修改菜单项 this->SetMenu(&m_Menu); //将菜单关联到窗口
void CMy83Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_Menu.DrawItem(lpDrawItemStruct); CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct); }
void CMy83Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_Menu.MeasureItem(lpMeasureItemStruct); CDialogEx::OnMeasureItem(nIDCtl, lpMeasureItemStruct); }