VC 创建一个图标菜单

步骤如下:

(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; //菜单项数量(图标数,高度,宽度增量)

(5)在CMenuItem 头文件声明成员变量

CMenuItem	m_ItemLists[MAX_MENUCOUNT];		//菜单项信息
	int			m_Index;						//临时索引
	int			m_IconIndex;					//菜单项图标索引
	CImageList	m_ImageList;					//存储菜单项图标

(6)像程序导入六个图标资源,并且在CMenIcon类构造函数中,初始化图像列表

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));			//添加图标
}

(7)在CMenuIcon类中添加AttachMenu方法

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);			//绘制菜单项文本
}

(11)在CMenuIcon类中添加DrawItemIcon函数,用于绘制图标

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));	//用另一种颜色填充矩形
	}
}

(15)重载CMenuIcon类的DrawItem方法,根据菜单项不不同状态绘制菜单项

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);						//将菜单关联到窗口

(18)重载对话框的OnDrawItem方法,在方法中调用菜单类中的DrawItem()方法

void CMy83Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	m_Menu.DrawItem(lpDrawItemStruct);
	CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

(19)重载对话框的OnMeasureItem方法,在该方法中调用菜单栏的MeasureItem方法

void CMy83Dlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	m_Menu.MeasureItem(lpMeasureItemStruct);
	CDialogEx::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}

运行结果如下:








评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值