转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42889709html
大概半年前我写过博客说明怎么改造duilib的原代MenuDemo来支持消息发送(地址为:http://blog.csdn.net/zhuhongshu/article/details/38253297),然后在仿酷狗项目里也用到了菜单类,而且菜单类岁仿酷狗一块儿开源了。可是仿酷狗里面的菜单是专门针对仿酷狗的需求而修改的,因此通用性还不够。考虑到菜单也比较经常使用。因此今天就把菜单控件重整,修改成通用的控件,而且把它集成了到个人duilib库里,能够直接使用。c++
在此我把通用菜单控件的使用方法说明一下,源码和Demo能够在个人duilib库中下载到。函数
1、首先看看这个菜单的功能:布局
一、能够展示多级菜单测试
二、可内嵌自定义控件,而且控件能够向主窗体发送消息,如图的红色叹号就是个按钮控件,能够制做酷狗音乐的托盘菜单的播放暂停按钮和进度控制进度条。优化
三、菜单拥有阴影效果(使用我库里的阴影类完成)ui
四、菜单能够自定义前方显示小图标,而且能够控制图标的大小和是否显示spa
五、菜单能够根据是否拥有子菜单决定是否显示小箭头.net
六、菜单能够添加分割线(控制分割线的样式和位置)指针
七、每一个菜单项均可以实现复选或者单选功能
八、优化菜单的xml描述文件,编写方便容易
九、能够经过键盘的按钮控制菜单的选项
十、每一个菜单项的高度和宽度是任意调整的
2、接着是我更新后的属性列表:
<Menu parent="CListUI" notifies="setfocus killfocus timer menu itemselect windowinit(root)"> <Attribute name="inset" default="0,0,0,0" type="RECT" comment="菜单的高度等于全部菜单项的高度之和,加上inset属性的top和bottom"/> <!-- Menu标签的属性要经过Default来定义,为了让下级菜单也能拥有一样的外观,其余属性设置见List --> </Menu> <MenuElement parent="CListContainerElementUI" notifies="click valuechanged WM_MENUCLICK"> <Attribute name="icon" default="" type="STRING" comment="菜单项的图标图片"/> <Attribute name="iconsize" default="0,0" type="SIZE" comment="图片的大小,最大为26x26"/> <Attribute name="checkitem" default="false" type="BOOL" comment="是否有复选功能"/> <Attribute name="ischeck" default="false" type="BOOL" comment="是否被选中(前提是开启了复选功能,复选功能属性应该写在本属性的前面)"/> <Attribute name="linetype" default="false" type="BOOL" comment="是不是分割线(开启后将不会显示图标)"/> <Attribute name="linepadding" default="29,0,7,0" type="RECT" comment="分割线的外边据"/> <Attribute name="linecolor" default="0xFFBCBFC4" type="DWORD" comment="分割线的颜色"/> <Attribute name="expland" default="false" type="BOOL" comment="是否显示下级菜单的小三角图片(须要经过Default标签设置ExplandIcon属性图片的路径)"/> <Attribute name="height" default="30" type="INT" comment="菜单项高度(分割线默认高度是6)"/> </MenuElement>
<?xml version="1.0" encoding="utf-8"?> <Window showshadow="true" shadowimage="shadow.png" shadowcorner="23,13,23,33"> <Font name="微软雅黑" size="12" bold="false" default="true" /> <Font name="微软雅黑" size="12" bold="true"/> <!-- Menu标签的属性要经过Default来定义,为了让下级菜单也能拥有一样的外观 --> <Default name="Menu" value="bordersize="1" borderround="2,2" bordercolor="0x303132" inset="2,2,2,2" itemtextpadding="30,0,0,0" bkimage="file='menu_bk.png' corner='26,2,2,2' source='6,6,44,24'" itemselectedbkcolor="0xFF338ACA"" /> <!-- ExplandIcon属性定义了下级菜单的小图标的样子 --> <Default name="ExplandIcon" value="menu_expand.png" /> <Menu> <MenuElement text="菜单测试0" expland="true" > <MenuElement text="菜单测试01" id="102"/> <MenuElement text="菜单测试02" /> </MenuElement> <MenuElement height="120" > <VerticalLayout bkcolor="#FFFFFFFE"> <Button name="Menu_btn" height="118" normalimage="error.png" hotimage="check_hover.png" pushedimage="check_pressed.png"/> </VerticalLayout> </MenuElement> <MenuElement name="Menu_Test1" text="菜单测试3" icon="right.png" iconsize="9,9" checkitem="true" ischeck="true" /> <MenuElement name="Menu_Test2" text="菜单测试31" /> <MenuElement name="Menu_Test3" text="菜单测试32" icon="right.png" iconsize="9,9" checkitem="true" ischeck="true" /> <MenuElement linetype="true" /> <MenuElement text="菜单测试4" icon="right.png" iconsize="9,9" expland="true" > <MenuElement text="菜单测试5" expland="true" icon="WebSit.png" > <MenuElement text="菜单测试6" icon="Virus.png" /> <MenuElement text="菜单测试7" /> </MenuElement> <MenuElement text="菜单测试8" expland="true"> <MenuElement text="菜单测试a" /> <MenuElement text="菜单测试b" /> </MenuElement> </MenuElement> </Menu> </Window>
一、须要经过Default来定义Menu的样式,这是为了可让全部菜单(包括各个下级菜单)使用统一的样式
二、用Default标签订义ExplandIcon属性来制定下级菜单的小图标的路径
三、MenuElement若是要用单选或者复选功能,checkitem属性要写在ischeck属性前面
四、指定Menu的inset内边距属性的top和bottom属性,会自动让菜单增高(不少状况须要这样作来设置菜单的内边距)
五、MenuElement的linepadding属性能够设置分割线的外边距,默认为"29,0,7,0",这个值要根据实际的素材和需求来设置
4、使用菜单的c++代码:
菜单的建立:
CMenuWnd* pMenu = new CMenuWnd(); CPoint point = msg.ptMouse; ClientToScreen(m_hWnd, &point); pMenu->Init(NULL, _T("menutest.xml"), point, &m_PaintManager, &m_MenuCheckInfo);
/* * @pOwner 一级菜单不要指定这个参数,这是菜单内部使用的 * @xml 菜单的布局文件 * @point 菜单的左上角坐标 * @pMainPaintManager 菜单的父窗体管理器指针 * @xml 保存菜单的单选和复选信息结构指针 * @dwAlignment 菜单的出现位置,默认出如今鼠标的右下侧。 */ void Init(CMenuElementUI* pOwner, STRINGorID xml, POINT point, CPaintManagerUI* pMainPaintManager, map<CDuiString,bool>* pMenuCheckInfo = NULL, DWORD dwAlignment = eMenuAlignment_Left | eMenuAlignment_Top);
使用new在堆上建立菜单控件(菜单会本身销毁内存)。本身主动建立菜单时第一参数直接填写NULL就能够;若是须要用到单选和复选功能就须要给控件指定一个map,来保存复选数据;若是须要控制菜单出现的位置,能够修改dwAlignment参数,参数能够设置eMenuAlignment_Left , eMenuAlignment_Top ,eMenuAlignment_Right ,eMenuAlignment_Bottom 四种值,具体用法参见demo。
菜单的消息响应:
这个菜单类支持响应菜单内嵌的控件(好比按钮或者滑动条控件,这个经常使用在作播放器的菜单上),内嵌控件的消息响应和普通的消息响应彻底同样,目前支持click消息和valuechanged消息(能够根据需求再增长),可是注意不能够在这些消息相应代码弹出像是MessageBox这样的模态对话框,缘由见我以前写的博客。
单击每一个菜单项的消息响应方法是,接收WM_MENUCLICK消息,这是我自定义的消息,处理这个消息时能够任意弹出模态对话框。一般消息响应的方法是重写WindowImplBase类的HandleCustomMessage函数来处理自定义消息(若是没有继承WindowImplBase类就本身写相似的函数功能),而后处理WM_MENUCLICK消息。处理代码以下:
LRESULT CFrameWnd::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (uMsg == WM_MENUCLICK) { CDuiString *strMenuName = (CDuiString*)wParam; bool bChecked = (bool)lParam; if ( *strMenuName == _T("Menu_Test1")) { if (bChecked) { MessageBox(m_hWnd, L"你选中Menu_Test1", L"", 0); } else { MessageBox(m_hWnd, L"你取消Menu_Test1", L"", 0); } } else if ( *strMenuName == _T("Menu_Test2")) { MessageBox(m_hWnd, L"你单击了Menu_Test2", L"", 0); } else if ( *strMenuName == _T("Menu_Test3")) { if (bChecked) { MessageBox(m_hWnd, L"你选中Menu_Test3", L"", 0); } else { MessageBox(m_hWnd, L"你取消Menu_Test3", L"", 0); } } delete strMenuName; } bHandled = false; return 0; }
菜单控件源码:
菜单控件的源码相对较多,我就不直接贴出来了,须要的朋友能够直接下载个人duilib库来查看,里面已经附带了菜单使用Demo和对应源码:点击打开连接
2015.1.19 Redrain
QQ:491646717