分享
 
 
 

自绘菜单的实现

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

文章标题:原 作 者:querw

原 出 处:www.vczx.com

发 布 者:querw

发布类型:原创

发布日期:2004-08-02

下载本文所附源代码

程序运行效果截图:

自绘菜单实现

作者:querw(北方工业大学 2000级计算机4班)

邮箱:querw@sina.com

在VCKBASE上读到<<一种漂亮的自绘菜单>> (http://www.vckbase.com/document/viewdoc/?id=537)

作者:郑恒 (lbird).应用到我的工程里后发现:文章中提到的效果能很好的实现,但是有一点不方便:需要映射

WM_DRAWITEM和WM_MEASUREITEM消息才能实现自画功能.这对于一个基于对话框的工程,或者

仅仅需要弹出式菜单的工程来说很不方便.网上有一种很有名的自绘菜单:BCMenu

(http://www.rocscience.com/~corkum/BCMenu.html)

(在附带工程中也有BCMenu),在使用它的时候并不需要映射上述的两个消息就能实现自绘效果.这个问题让我觉

得很困惑,MSDN也说明:MeasureItem()和DrawItem()两个虚函数是由框架调用的,并不用手工映射.可是若

不映射上述的两个消息则显示不正常.(我查看了好多资料,直到现在还是不明白原因,呵呵:))既然BCMenu

可以不用映射WM_DRAWITEM和WM_MEASUREITEM就能实现自画功能,那么它肯定经过了特殊处理.果然

,BCMenu::LoadMenu()对整个菜单作了处理.我注意到,如果菜单是弹出式的,那么不需要映射WM_DRAWITEM

和WM_MEASUREITEM就能实现自画功能.于是我在CMenuEx::LoadMenu()中重新构建了整个菜单,

把所有的子菜单创建为弹出式的菜单使用API函数::CreatePopupMenu(),代码如下:

BOOL CMenuEx::LoadMenu(UINT uMenu)

{

//重新读入菜单,创建为popup菜单,才能自画(由框架调用MesureItem() 和 DrawItem()

HMENU hMenu = ::CreateMenu();

this->Attach(hMenu);

CMenu Menu; //临时菜单(使用CMenu的LoadMenu()函数读入菜单,并以之为蓝本构建新的菜单)

UINT uID;

Menu.LoadMenu(uMenu);

for(int i = 0; i < (int)Menu.GetMenuItemCount(); i++)

{

uID = Menu.GetMenuItemID(i);

if(uID == 0) //分隔符

{

::AppendMenu(hMenu,MF_SEPARATOR,0,NULL);

}

else if((int)uID == -1) //弹出菜单(即子菜单)

{

CMenu *pSubMenu = Menu.GetSubMenu(i);

//创建子菜单

HMENU hSubMenu = ::CreatePopupMenu();

CString strPopup;

Menu.GetMenuString(i,strPopup,MF_BYPOSITION);

::InsertMenu(hMenu,i,MF_BYPOSITION | MF_POPUP | MF_STRING,(UINT)hSubMenu,strPopup);

//对子菜单递归调用ChangeMenuStyle(),把子菜单改为MF_OWNERDRAW风格

ChangeMenuStyle(pSubMenu,hSubMenu);

}

else //正常的菜单项

{

CString strText;

Menu.GetMenuString(uID,strText,MF_BYCOMMAND);

AppendMenu(MF_STRING,uID,strText);

}

}

Menu.DestroyMenu(); //销毁临时菜单

return TRUE;

}

void CMenuEx::ChangeMenuStyle(CMenu *pMenu,HMENU hNewMenu)

{

//关联为CMenuEx(关联为CMenuEx后才能自动重画

//原因不明(CMenu封装的结果?)

CMenuEx *pNewMenu;

pNewMenu = new CMenuEx;

pNewMenu->Attach(hNewMenu);

m_SubMenuArr.Add(pNewMenu);

UINT uID;

int nItemCount = pMenu->GetMenuItemCount();

for(int i = 0; i < nItemCount; i++)

{

uID = pMenu->GetMenuItemID(i);

if(uID == 0) //分隔符

{

::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);

//pNewMenu->AppendMenu(MF_SEPARATOR,0,NULL);

CString strText;

MENUITEM *pMenuItem = new MENUITEM;

pMenuItem->uID = 0;

pMenuItem->uIndex = -1;

pMenuItem->uPositionImageLeft = -1;

pMenuItem->pImageList = &m_ImageList;

m_MenuItemArr.Add(pMenuItem);

::ModifyMenu(hNewMenu,i,MF_BYPOSITION | MF_OWNERDRAW,-1,(LPCTSTR)pMenuItem);

}

else if(uID == -1) //弹出菜单(即子菜单)

{

CMenu *pSubMenu = pMenu->GetSubMenu(i);

HMENU hPopMenu = ::CreatePopupMenu();

CString strPopup;

pMenu->GetMenuString(i,strPopup,MF_BYPOSITION);

::InsertMenu(hNewMenu,i,MF_BYPOSITION | MF_POPUP,(UINT)hPopMenu,strPopup);

MENUITEM *pMenuItem = new MENUITEM;

pMenuItem->uID = -1;

pMenuItem->strText = strPopup;

pMenuItem->uIndex = -1;

pMenuItem->uPositionImageLeft = -1;

pMenuItem->pImageList = &m_ImageList;

m_MenuItemArr.Add(pMenuItem);

::ModifyMenu(hNewMenu,i,MF_BYPOSITION | MF_OWNERDRAW,-1,(LPCTSTR)pMenuItem);

ChangeMenuStyle(pSubMenu,hPopMenu);

}

else //正常的菜单项

{

CString strText;

pMenu->GetMenuString(uID,strText,MF_BYCOMMAND);

MENUITEM *pMenuItem = new MENUITEM;

pMenuItem->uID = pMenu->GetMenuItemID(i);

pMenu->GetMenuString(pMenuItem->uID,pMenuItem->strText,MF_BYCOMMAND);

pMenuItem->uIndex = -1;

pMenuItem->uPositionImageLeft = -1;

pMenuItem->pImageList = &m_ImageList;

m_MenuItemArr.Add(pMenuItem);

UINT uState = pMenu->GetMenuState(i,MF_BYPOSITION);

::AppendMenu(hNewMenu,MF_OWNERDRAW | MF_BYCOMMAND | uState,uID,(LPCTSTR)pMenuItem);

}

}

}

这样,利用标注的CMenu::LoadMenu()函数读入菜单,并根据这个菜单重新构建一个新的菜单,在新菜单中把所有的

子菜单创建为弹出式菜单并关联一个CMenuEx类.根据需要,我提供了一个CMenuEx::LoadToolBar(UINT

uToolBar, UINT uFace)接口.请注意它的两个参数:uToolBar

是工具条的资源,uFace是一个替代位图的资源ID.因为VC6.0中做一个真彩工具栏并不是一件容易的事,所以我

做了一个小动作:用IDE的资源编辑器随便编辑一个工具条,只要ID和菜单ID相对应即可,然后可以用外部编辑器

编辑好真正要使用的位图(顺序和工具条资源的顺序一样),并把该位图作为uFace参数传入,菜单就可以有真彩

图标了.

CMenuEx还提供了如下三个接口

BOOL ModifyMenuEx()

BOOL AppendMenuEx()

BOOL RemoveMenuEx()

功能一目了然,只是增加了对自绘风格的处理,应用的时候只要像调用普通的CMenu::AppendMenu()等函数一样

就自动拥有自绘风格了.我写这篇文章的目的在于提出菜单派生类调用MeasureItem()和DrawItem()的问题

.至于实现漂亮的菜单界面主要工作当然还是在DrawItem()函数中做,有特殊需要的可以自行定义MENUITEM

结构,重新写DrawItem()函数.我没有提供设置菜单附加位图的具体代码,相信这个不是问题,你可

以很容易的通过重写DrawItem()实现.有必要提醒的是:有关一个菜单项的信息最好能完全从一个MENUITEM

结构中取得,使virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);

virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);

两个函数完全不依赖于CMenuEx类的数据成员.

要在工程中使用CMenuEx很简单:

1.把MenuEx.h和MenuEx.cpp加入到你的工程中

2.声明一个CMenuEx对象.例如m_Menu;

3.调用m_Menu.LoadMenu(IDR_MENU1);读入菜单

4.若需要使用菜单位图则调用m_Menu.LoodToolBar();

效果如下:

MenuEx.jpg,MenuExPopup.jpg

最后,对<<一种漂亮的自绘菜单>> 的作者郑恒给予我的帮助表示衷心感谢!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有