首先,在MFC中,具有PopUp屬性的菜單是不能用來做命令響應的。
在MFC中:
當點擊一個菜單項的時候,最先接受到菜單項消息的是CMainFrame框架類,CMainFrame框架類將會把菜單項消息交給它的子窗口View類,由View類首先進行處理;如果View類檢測到沒對該菜單項消息做響應,則View類把菜單項消息交由文檔類Doc類進行處理;如果Doc類檢測到Doc類中也沒對該菜單項消息做響應,則Doc類又把該菜單項消息交還給View類,由View類再交還給CMainFrame類處理。如果CMainFrame類查看到CMainFrame類中也沒對該消息做響應,則最終交給App類進行處理。
所以,其消息傳遞順序爲:View類--Doc類--CMainFrame類--App類。當然,菜單消息一旦在其中一個類中響應則不再在其它類中查找響應函數
windows消息的分類
(1)標準消息:除WM_COMMAND之外,所有以WM_開頭的消息。從CWnd類派生的都可以接收到這些消息。
(2)命令消息:來自菜單、加速鍵或工具欄按鈕的消息。這類消息都以WM_COMMAND呈現。在MFC中,通過菜單項的標識(ID)來區分不同的命令消息;在SDK中,通過消息的wParam參數識別。
(3)通告消息:由控件產生的消息,例如,按鈕的單擊,列表框的選擇等均產生此類消息,爲的是向其父窗口(通常是對話框)通知事件的發生。這類消息也是以WM_COMMAND形式呈現。——————從CCmdTarget派生的類,都可以接收到[命令消息]和[通告消息]。
在menu操作過程中,幾個函數需要了解:
1 CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜單欄對象指針。 2 CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu獲得指向彈出菜單對象指針 3 UINT CheckMenuItem( );//CMenu::CheckMenuItem添加(add)check marks(選擇標記)或者是刪除(remove)check marks,是針對菜單項的作用 4 BOOL SetDefaultItem();//CMenu::SetDefaultItem 5 BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 設置位圖標題菜單。 6 UINT EnableMenuItem();//CMenu::EnableMenuItem使菜單項有效,無效,或變灰。 7 BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在當前窗口上設置新菜單或移除菜單 8 HMENU Detach( );//CMenu::Detach Detaches a Windows menu from a CMenu object and returns the handle.
創建一個menu項的簡單過程:
1 CMenu menu;//定義爲局部對象 2 menu.LoadMenu(IDR_MAINFRAME); 3 SetMenu(&menu); 4 menu.Detach();//因爲局部對象
這裏menu對象作爲一個局部對象。使用Detach()從menu對象中分離窗口菜單句柄,從而當menu對象析構的時候窗口菜單資源不隨之銷燬。
命令更新機制:
菜單項狀態的維護是依賴於CN_UPDATE_COMMAND_UI消息,誰捕獲CN_UPDATE_COMMAND_UI消息,MFC就在其中創建一個CCmdUI對象。
在後臺操作系統發出WM_INITMENUPOPUP消息,然後由MFC的基類如CFrameWnd接管並創建一個CCmdUI對象和第一個菜單項相關聯,調用對象成員函數DoUpdate()(注:這個函數在MSDN中沒有找到說明)發出CN_UPDATE_COMMAND_UI消息,這條消息帶有指向CCmdUI對象的指針。此後同一個CCmdUI對象又設置爲與第二個菜單項相關聯,這樣順序進行,直到完成所有菜單項。
更新命令UI處理程序僅應用於彈出式菜單項上的項目,不能應用於永久顯示的頂級菜單項目。
利用調用TrackPopupMenu函數,創建ContextMenu(右鍵菜單):
1 void CMenu2View::OnRButtonDown(UINT nFlags, CPoint point) 2 { 3 CMenu menu; 4 menu.LoadMenu(IDR_MENU1); 5 CMenu *pPopup = menu.GetSubMenu(0); 6 ClientToScreen(&point);//將一個座標點或一個矩形區域座標轉換成屏幕座標。 7 pPopup->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,GetParent());//在指定位置以指定的方式顯示彈出菜單。 8 CView::OnRButtonDown(nFlags, point); 9 }
1)用資源管理器添加一個菜單資源
2)在鼠標右鍵消息響應函數中,加載菜單資源,並獲得要顯示的子菜單指針,並用該指針調用TrackPopupMenu函數便完成任務(但要注意:鼠標響應函數傳進來的座標是客戶區座標,而TrackPopupMenu函數中使用的是屏幕座標,在調用TrackPopupMenu前要調用ClientToScreen客戶區座標到屏幕座標的轉換)
3)彈出菜單上的消息,在路由的時候,仍然遵循View-DOC-MainFrame-APP的響應順序。
動態菜單編程:
一些有關的比較重要的函數:
1 CMenu::AppendMenu //Appends a new item to the end of a menu. 2 CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object. 3 CMenu::InsertMenu 4 //Inserts a new menu item at the position specified by nPosition and moves other items down the menu. 5 CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu. 6 CWnd::GetMenu //Retrieves a pointer to the menu for this window. 7 CMenu::DeleteMenu //Deletes an item from the menu.
1 CView* GetActiveView( ) const;//獲取當前視窗口指針(單文檔框架中)