MFC菜單消息漫談

 首先,在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;//獲取當前視窗口指針(單文檔框架中)
發佈了16 篇原創文章 · 獲贊 20 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章