1 .彈出菜單( Pop-up) 是不能用來作命令響應(yīng)的。
2 . MFC 中菜單項消息如果利用 ClassWizard 來對菜單項消息分別在上述四個類中進行響應(yīng),則菜單消息傳遞順序: View 類 --Doc 類 --CMainFrame 類 --App 類。菜單消息一旦在其中一個類中響應(yīng)則不再在其它類中查找響應(yīng)函數(shù)。
具體:
當(dāng)點擊一個菜單項的時候,最先接受到菜單項消息的是 CMainFrame 框架類, CMainFrame 框架類將會把菜單項消息交給它的子窗口 View 類,由 View 類首先進行處理;如果 View 類檢測到?jīng)]對該菜單項消息做響應(yīng),則 View 類把菜單項消息交由文檔類 Doc 類進行處理;如果 Doc 類檢測到 Doc 類中也沒對該菜單項消息做響應(yīng),則 Doc 類又把該菜單項消息交還給 View 類,由 View 類再交還給 CMainFrame 類處理。如果 CMainFrame 類查看到 CMainFrame 類中也沒對該消息做響應(yīng),則最終交給 App 類進行處理。
3 .消息的分類:標(biāo)準(zhǔn)消息,命令消息,通告消息。
[ 標(biāo)準(zhǔn)消息 ] :除 WM_COMMAND 之外,所有以 WM_ 開頭的消息。
[ 命令消息 ] :來自菜單、加速鍵或工具欄按鈕的消息。這類消息都以 WM_COMMAND 呈現(xiàn)。
在 MFC 中,通過菜單項的標(biāo)識( ID )來區(qū)分不同的命令消息;在 SDK 中,通過消息的 wParam 參數(shù)識別。
[ 通告消息 ] :由控件產(chǎn)生的消息,例如,按鈕的單擊,列表框的選擇等均產(chǎn)生此類消息,為的是向其父窗口(通常是對話框)通知事件的發(fā)生。這類消息也是以 WM_COMMAND 形式呈現(xiàn)。
說明:
1 )從 CWnd 派生的類,都可以接收到 [ 標(biāo)準(zhǔn)消息 ] 。
2 )從 CCmdTarget 派生的類,都可以接收到 [ 命令消息 ] 和 [ 通告消息 ] 。
4 .一個菜單攔可以有若干個子菜單,一個子菜單又可以有若干個菜單項等。對菜單欄的子菜單由左至右建立從 0 開始的索引。對特定子菜單的菜單項由上至下建立了從 0 開始的索引。訪問子菜單和菜單項均可以通過其索引或標(biāo)識(如果有標(biāo)識的話)進行。
相關(guān)重要函數(shù):
CMenu* GetMenu( ) ;//CWnd::GetMenu 得到窗口菜單欄對象指針。
CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu 獲得指向彈出菜單對象指針
UINT CheckMenuItem( );//CMenu::CheckMenuItem Adds check marks to or removes check marks from menu items in the pop-up menu.
BOOL SetDefaultItem();//CMenu::SetDefaultItem Sets the default menu item for the specified menu.
BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 設(shè)置位圖標(biāo)題菜單。
UINT EnableMenuItem();//CMenu::EnableMenuItem 使菜單項有效,無效,或變灰。
BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu 在當(dāng)前窗口上設(shè)置新菜單或移除菜單。
HMENU Detach( );//CMenu::Detach Detaches a Windows menu from a CMenu object and returns the handle.
說明:
1 )在計算子菜單菜單項的索引的時候,分隔欄符也算索引的。
2 ) int GetSystemMetrics() 獲取系統(tǒng)信息度量。可以用它來獲取菜單標(biāo)題的尺寸從而設(shè)置位圖標(biāo)題菜單中位圖的大小。
3 )在 MFC 中 MFC 為我們提供了一套命令更新機制,所有菜單項的更新都是由這套機制來完成的。所以要想利用 CMenu::EnableMenuItem 來自己控制菜單使用或不使用變灰等,必須要在 CMainFrame 的構(gòu)造函數(shù)中將變量 m_bAutoMenuEnable 設(shè)置為 FALSE 。
4 ) Create a CMenu object on the stack frame as a local, then call CMenu’s member functions to manipulate the new menu as needed. Next, call CWnd::SetMenu to set the menu to a window, followed immediately by a call to the CMenu object’s Detach member function. The CWnd::SetMenu member function sets the window’s menu to the new menu, causes the window to be redrawn to reflect the menu change, and also passes ownership of the menu to the window. The call to Detach detaches the HMENU from the CMenu object, so that when the local CMenu variable passes out of scope, the CMenu object destructor does not attempt to destroy a menu it no longer owns. The menu itself is automatically destroyed when the window is destroyed.
5 ) You can use the LoadMenuIndirect member function to create a menu from a template in memory, but a menu created from a resource by a call to LoadMenu is more easily maintained, and the menu resource itself can be created and modified by the menu editor.
6 ) EXAMPLE :
CMenu menu;// 定義為局部對象
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();// 這里 menu 對象作為一個局部對象。使用 Detach() 從 menu 對象中分離窗口菜單句柄,從而當(dāng) menu 對象析構(gòu)的時候窗口菜單資源不隨之銷毀。
5 .命令更新機制:
菜單項狀態(tài)的維護是依賴于 CN_UPDATE_COMMAND_UI 消息,誰捕獲 CN_UPDATE_COMMAND_UI 消息, MFC 就在其中創(chuàng)建一個 CCmdUI 對象。
在后臺操作系統(tǒng)發(fā)出 WM_INITMENUPOPUP 消息,然后由 MFC 的基類如 CFrameWnd 接管并創(chuàng)建一個 CCmdUI 對象和第一個菜單項相關(guān)聯(lián),調(diào)用對象成員函數(shù) DoUpdate() (注:這個函數(shù)在 MSDN 中沒有找到說明)發(fā)出 CN_UPDATE_COMMAND_UI 消息,這條消息帶有指向 CCmdUI 對象的指針。此后同一個 CCmdUI 對象又設(shè)置為與第二個菜單項相關(guān)聯(lián),這樣順序進行,直到完成所有菜單項。
更新命令 UI 處理程序僅應(yīng)用于彈出式菜單項上的項目,不能應(yīng)用于永久顯示的頂級菜單項目。
說明:
1 )可以手工或用 ClassWizard 來給菜單項添加 UPDATE_COMMAND_UI 消息響應(yīng),利用響應(yīng)函數(shù)中傳進來的 CCmdUI 對象指針可完成設(shè)置菜單項可使用,不可使用,變灰,設(shè)置標(biāo)記菜單等操作。
6 .如果要想讓工具欄上的某個圖標(biāo)與菜單項的某個菜單相關(guān)聯(lián),只需要將圖標(biāo)的 ID 設(shè)置為該菜單項的 ID 。
工具欄圖標(biāo)的索引記數(shù)順序是:從做至右從 0 開始,分隔符也算索引號。
7 .利用向項目中添加 VC 的 POPMENU 控件: Project->Add to Project->Components and Controls..
系統(tǒng)增加的內(nèi)容: A ,一個菜單資源; B ,在派生 View 類中增加了 OnContextMenu() 函數(shù)
說明:
1 ) CWnd::OnContextMenu Called by the framework when the user has clicked the right mouse button (right clicked) in the window. You can process this message by displaying a context menu using the TrackPopupMenu.
2 ) BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );
//CMenu::TrackPopupMenu Displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. A floating pop-up menu can appear anywhere on the screen.
8 .利用調(diào)用 TrackPopupMenu 函數(shù),手工添加彈出菜單:
1 )用資源管理器添加一個菜單資源
2 )在鼠標(biāo)右鍵消息響應(yīng)函數(shù)中,加載菜單資源,并獲得要顯示的子菜單指針,并用該指針調(diào)用 TrackPopupMenu 函數(shù)便完成任務(wù)(但要注意:鼠標(biāo)響應(yīng)函數(shù)傳進來的坐標(biāo)是客戶區(qū)坐標(biāo),而 TrackPopupMenu 函數(shù)中使用的是屏幕坐標(biāo),在調(diào)用 TrackPopupMenu 前要調(diào)用 ClientToScreen 客戶區(qū)坐標(biāo)到屏幕坐標(biāo)的轉(zhuǎn)換)
事例代碼:
CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pPopup=menu.GetSubMenu(0);
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);
說明:
CWnd::ClientToScreen(..);// 將一個坐標(biāo)點或一個矩形區(qū)域坐標(biāo)轉(zhuǎn)換成屏幕坐標(biāo)。
CMenu::TrackPopupMenu(..);// 在指定位置以指定的方式顯示彈出菜單。
CWnd::ScreenToClient(..);
//Converts the screen coordinates of a given point or rectangle on the display to client coordinates.
9 .當(dāng)彈出菜單屬于框架窗口的時候(可在 TrackPopupMenu 函數(shù)參數(shù)中設(shè)置),彈出菜單上的消息,在路由的時候,仍然遵循 View-DOC-MainFrame-APP 的響應(yīng)順序。
10 .動態(tài)菜單編程:
所有的資源對象都有一個數(shù)據(jù)成員保存了資源的句柄。
CMenu::AppendMenu //Appends a new item to the end of a menu.
CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object.
CMenu::InsertMenu
//Inserts a new menu item at the position specified by nPosition and moves other items down the menu.
CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu.
CWnd::GetMenu //Retrieves a pointer to the menu for this window.
CMenu::DeleteMenu //Deletes an item from the menu.
11 .手動給動態(tài)菜單項添加響應(yīng)函數(shù):
在 Resource.h 中可以添加資源的 ID
在頭文件中寫消息函數(shù)原型
在代碼文件中添加消息映射和添加消息響應(yīng)函數(shù)
說明:
可以先創(chuàng)建一個臨時的菜單項,設(shè)置它的 ID 和動態(tài)菜單項的一致,然后對它用向?qū)нM行消息響應(yīng),然后刪除臨時菜單。
再在代碼文件中把消息映射放到宏外(注意一定要放到宏外面,因為 CLASSWIZARD 發(fā)現(xiàn)菜單刪除了,同時要把其宏對里的消息映射也刪除掉的)
12 . CWnd::DrawMenuBar
//Redraws the menu bar. If a menu bar is changed after Windows has created the window, call this function to draw the changed menu bar
CWnd::GetParent //get a pointer to a child window’s parent window (if any).
CWnd::Invalidate // 注意其參數(shù)的作用
13 .集合類:
CStringArray , CStringArray , CDWordArray , CPtrArray , CStringArray , CUIntArray , CWordArray
其中成員函數(shù):
CArray::GetAt
CArray::Add
14 .命令消息是到 OnCommand 函數(shù)的時候完成路由的。
由于 CWnd::OnCommand 是個虛函數(shù),可以在框架類中重寫 OnCommand 函數(shù),從而可以截獲菜單消息使它不再往下( VIEW 類)路由。
例:
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
int MenuCmdId=LOWORD(wParam);// 取命令 ID
CMenu2View *pView=(CMenu2View*)GetActiveView();// 獲取當(dāng)前 VIEW 類指針
if(MenuCmdId>=IDM_PHONE1 && MenuCmdId<IDM_PHONE1+pView->m_strArray.GetSize())// 消息范圍判斷
{
CClientDC dc(pView);
dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));
return TRUE;
// 函數(shù)返回,避免調(diào)用 CFrameWnd::OnCommand 函數(shù),在 CFrameWnd::OnCommand 中截獲的消息會交由 VIEW 類處理
}
return CFrameWnd::OnCommand(wParam, lParam);
// 調(diào)用基類 OnCommand 函數(shù),在 CFrameWnd::OnCommand 中截獲的消息會交由 VIEW 類處理
}
MSDN 說明:
virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );
//The framework calls this member function when the user selects an item from a menu, when a child control sends a notification message, or when an accelerator keystroke is translated.
OnCommand processes the message map for control notification and ON_COMMAND entries, and calls the appropriate member function.
Override this member function in your derived class to handle the WM_COMMAND message. An override will not process the message map unless the base class OnCommand is called.
15 . LOWORD 與 HIWORD 宏
WORD LOWORD(
DWORD dwValue // value from which low-order word is retrieved
);
WORD HIWORD(
DWORD dwValue // value from which high-order word is retrieved
);
//The LOWORD macro retrieves the low-order word from the given 32-bit value.
//The HIWORD macro retrieves the high-order word from the given 32-bit value.
16 。 CFrameWnd::GetActiveView
CView* GetActiveView( ) const;// 獲取當(dāng)前視窗口指針(單文檔框架中)
17 .源文件是單獨參與編譯的。