有關菜單的操作主要用到CMenu類,當然也可用相應API函數,CMenu類只是MFC對API中操作菜單的函數的封裝而已。 不過能用類就盡量用類,類的組織方式好呗,代碼看著也舒服。 若是SDK編程,那就用API吧 。
CMenu menuMain,menu1; //首先 定義CMenu對象
1. 用LoadMenu函數從資源加載
menuMain.LoadMenu(IDR_MAINFRAME); //從資源加載,這裡使用SDI的主菜單資源
2. 用CreateMenu函數創建
menu1.CreateMenu(); //創建菜單,還沒有菜單項
// ID_TEST1 在Resource.h 中定義,隨便給個整數值,不要和已有的重復就行了 menu1.AppendMenu(MF_STRING,ID_TEST1,"Test1"); // 第一項菜單項 menu1.AppendMenu(MF_STRING,ID_TEST2,"Test2"); // 第二項菜單項 menu1.InsertMenu(1,MF_BYPOSITION|MF_STRING,(UINT)ID_TEST1,"ID_TEST1"); // 在第二項菜單項前添加新菜單項
同樣用AppendMenu()、InsertMenu()函數。不過要注意參數的設置。
menu1.AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT) menuMain.GetSubMenu(0) ->m_hMenu,"子菜單");
//第二個參數是菜單的句柄HMENU
用DeleteMenu()、RemoveMenu()函數來刪除指定位置的菜單/菜單項。
兩者區別:如果菜單項是一個彈出式菜單,那麼DeleteMenu和RemoveMenu之間的區別就很重要。DeleteMenu清除彈出式菜單,但RemoveMenu不清除它。一個是徹底的刪除,一個只是移除.
MSDN:
1.The DeleteMenu function destroys the handle to the menu or submenu and frees the memory used by the menu or submenu.
它使菜單或者子菜單的handle無效(destroys)。
2. RemoveMenu does not destroy the menu or its handle, allowing the menu to be reused.
可以再利用,並不從內存中將menu刪除。
CMenu menu1; menu1.CreatePopupMenu(); //動態創建彈出式菜單對象 menu1.AppendMenu(MF_STRING,ID_TEST1," 菜單項1"); menu1.AppendMenu(MF_STRING,ID_TEST2," 菜單項2"); menu1.InsertMenu(2,MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT) menuMain.m_hMenu,"子菜單"); //添加子菜單 CPoint pt; GetCursorPos(&pt); menu1.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this); menu1.DestroyMenu();
1. 若是資源中添加的菜單可用Class Wizard添加菜單的響應事件。
2. 若是通過代碼創建的菜單,要手工實現菜單的消息映射。本例是在CmainFrame類中,當然也可在View類、Doc類中,基於對話框的同樣也可以。
1) 在.h文件中
// Generated message map functions protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnChangmenuitem(); //這裡添加菜單命令處理函數的聲明 //}}AFX_MSG DECLARE_MESSAGE_MAP()2) 在.cpp文件中,
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(IDM_CHANGMENUITEM, OnChangmenuitem) //這裡添加,注意沒有’ ;’ //}}AFX_MSG_MAP END_MESSAGE_MAP() void CMainFrame::OnChangmenuitem() { // 這裡寫你要如何處理的代碼 …… }其他方法:
若菜單ID值是連續的,最好用ON_COMMAND_RANGE來映射消息處理函數,可以在一個函數中處理一個范圍內的所有消息。
當用戶按下某個菜單項,會發出一個WM_COMMAND消息,而菜單項的ID號,就包含在參數wParam的低位中.
BOOL CYourView::OnCommand(WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class UINT m_nItemID=LOWORD(wParam); if (m_nItemID==ID_YOURITEM) //ID_YOURITEM為你加入菜單項時指定的ID號 { //在這裡放入響應的代碼 } return CScrollView::OnCommand(wParam, lParam); }對於右鍵菜單可以通過TrackPopupMenu的返回值來處理。在參數uFlags中設置TPM_ RETURNCMD,這樣返回值就是你選擇的菜單項的ID,然後可以根據ID來處理。
TrackPopupMenu(TPM_ RETURNCMD ,pt.x,pt.y,this);
MSDN:If you specify TPM_RETURNCMD in the uFlags parameter, the return value is the menu-item identifier of the item that the user selected.
DrawMenuBar () ; //當您改變菜單時,需要重畫菜單才能顯示所做的改變
GetSystemMenu () ; //取得窗口控制窗口
GetMenu() //取得當前程序使用的菜單
GetSubMenu() //取得子菜單
應使用CMenu類的Detach()成員函數從Cmenu對象中分離出菜單句柄,避免對象失效後程序出錯。
如:
CMenu menu; menu.CreatePopupMenu(); //動態創建彈出式菜單對象 menu.AppendMenu(0,ID_TEST1,"Test1"); menu.AppendMenu(0,ID_TEST2,"Test2"); CMenu* menuMain = GetMenu(); //取得程序主菜單 需在CMainFrame類中 menuMain->AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT)menu.m_hMenu,"子菜單1"); menu.Detach(); //直接用menu.m_hMenu在運行時出錯,menu對象在這個事件結束就銷毀了 DrawMenuBar();