轉載請說明原出處,謝謝~~: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