Lesson5: 菜單編程

1.  MFC中的頂層菜單默認爲彈出菜單(Pop-up),它是不能用來作命令響應的,當取消Pop-up選項後可接受命令響應

 

2.  消息的分類:標準消息命令消息通告消息

(1)標準消息

         除WM_COMMAND之外,所有以WM_開頭的消息。從CWnd類派生的類都可以接收到這一消息

(2)命令消息

         來自菜單、加速鍵或工具欄按鈕的消息。這類消息都以WM_COMMAND呈現

        在MFC中,通過菜單項的標識(ID)來區分不同的命令消息;在SDK中,通過消息的wParam參數識別。

        從CCmdTarget(CWnd的父類)派生的類都可以接收到這一類消息

(3)通告消息

         由控件產生的消息,例如,按鈕的單擊,列表框的選擇等均產生此類消息,爲的是向其父窗口(通常是對話框)

         通知事件的發生。這類消息也是以WM_COMMAND形式呈現從CCmdTarget(CWnd的父類)派生的類都可以

         接收到這一類消息

總結:凡是從CWnd派生的類,既可以接收標準消息,也可以接收命令消息和通告消息。而對於那些從CCmdTarget派生的類,則只能接收命令消息和通告消息,不能接收標準消息。

 

3.  MFC中菜單項消息如果利用ClassWizard來對菜單項消息分別在上述四個類中進行響應,則菜單消息傳遞順序View類--Doc類--CMainFrame類--App類

(1)菜單消息一旦在其中一個類中響應則不再在其它類中查找響應函數。

(2)菜單消息與前面介紹的標準消息的實現機制是相類似的,都是在消息響應函數原型(頭文件),消息映射宏

       (源文件)和消息函數實現(源文件)中添加代碼

(3)注意:文檔類與應用程序類都是由CCmndTarget類派生,所以可以接收菜單命令消息,但不能接收標準消息

                  (只能由CWnd類派生纔可以)。

(4)具體消息路由過程

         當點擊一個菜單項的時候,最先接受到菜單項消息的是CMainFrame框架類CMainFrame框架類將會把菜單項

         消息交給它的子窗口View,由View類首先進行處理;如果View類檢測到沒對該菜單項消息做響應,則View

         把菜單項消息交由文檔類Doc類進行處理;如果Doc類檢測到Doc類中也沒對該菜單項消息做響應,則Doc類又把

         該菜單項消息交還給ViewView類再交還給CMainFrame類處理。如果CMainFrame類查看到CMainFrame

         類中也沒對該消息做響應,則最終交給App類進行處理

 

4. 一個菜單欄可以有若干個子菜單,一個子菜單又可以有若干個菜單項等。對菜單欄的子菜單由左至右建立從0開始的索引。對特定子菜單的菜單項由上至下建立了從0開始的索引。訪問子菜單和菜單項均可以通過其索引或標識(如果有標識的話)進行

相關重要函數:

CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜單欄對象指針。

CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu獲得指向彈出菜單對象指針

UINT CheckMenuItem( );//CMenu::CheckMenuItem 添加選中標識

BOOL SetDefaultItem();//CMenu::SetDefaultItem 爲指定菜單設置缺省菜單項

BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 設置位圖標題菜單。

UINT EnableMenuItem();//CMenu::EnableMenuItem使菜單項有效,無效,或變灰。

BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在當前窗口上設置新菜單或移除菜單。

HMENU Detach( ); //CMenu::Detach斷開一個菜單資源與相關的類對象句柄關聯,可以定義局部對象,在使用完後調用Detach函數,則不會因爲局部對象影響使用

說明:

(1)在計算子菜單菜單項的索引的時候,分隔欄符也算索引

(2int GetSystemMetrics()獲取系統信息度量。可以用它來獲取菜單標題的尺寸(後面還會使用到獲取屏目尺寸)

         從而設置位圖標題菜單中位圖的大小。

(3MFCMFC爲我們提供了一套命令更新機制,所有菜單項的更新都是由這套機制來完成的。所以要想利

         用CMenu::EnableMenuItem來自己控制菜單使用或不使用變灰等,必須要在CMainFrame的構造函數中將變量

         m_bAutoMenuEnable設置爲FALSE

例如

CMenu menu;//定義爲局部對象
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();// 這裏menu對象作爲一個局部對象。使用Detach()從menu對象中分離窗口菜單句柄,從而當menu對象
                 //析構的時候窗口菜單資源不隨之銷燬。

5. 命令更新機制

菜單項狀態的維護是依賴於CN_UPDATE_COMMAND_UI消息,誰捕獲CN_UPDATE_COMMAND_UI消息,MFC就在其中創建一個CCmdUI對象。

過程如下:

(1)在後臺操作系統發出WM_INITMENUPOPUP消息

(2)然後由MFC的基類如CFrameWnd接管並創建一個CCmdUI對象和第一個菜單項相關聯,調用對象成員函數DoUpdate()發出CN_UPDATE_COMMAND_UI消息,這條消息帶有指向CCmdUI對象的指針。

(3)此後同一個CCmdUI對象又設置爲與第二個菜單項相關聯,這樣順序進行,直到完成所有菜單項。

更新命令UI處理程序僅應用於彈出式菜單項上的項目,不能應用於永久顯示的頂級菜單項目

說明:

可以手工或用ClassWizard來給菜單項添加UPDATE_COMMAND_UI消息響應,利用響應函數中傳進來的CCmdUI對象指針可完成設置菜單項可使用,不可使用,變灰,設置標記菜單等操作。

 

6. 如果要想讓工具欄上的某個圖標與菜單項的某個菜單相關聯,只需要將圖標的ID設置爲該菜單項的ID

    工具欄圖標的索引記數順序是:從做至右從0開始,分隔符也算索引號。

 

7. 利用向項目中添加VC的POPMENU控件Project->Add to Project->Components and Controls..

系統增加的內容:A.一個菜單資源;B. 在派生View類中增加了OnContextMenu()函數

說明:

(1CWnd::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.

(2BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );

//CMenu::TrackPopupMenu Displays a floating popup 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. 利用調用TrackPopupMenu函數,手工添加彈出菜單

(1)用資源管理器添加一個菜單資源

(2)在鼠標右鍵消息響應函數中,加載菜單資源,並獲得要顯示的子菜單指針,並用該指針調用TrackPopupMenu函數

          便完成任務(注意:鼠標響應函數傳進來的座標是客戶區座標,而TrackPopupMenu函數中使用的是屏幕坐

          標,在調用TrackPopupMenu前要調用ClientToScreen客戶區座標到屏幕座標的轉換

代碼:

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(..);//將一個座標點或一個矩形區域座標轉換成屏幕座標。

CMenu::TrackPopupMenu(..);//在指定位置以指定的方式顯示彈出菜單。

CWnd::ScreenToClient(..);

//Converts the screen coordinates of a given point or rectangle on the display to client coordinates. 

 

9. 當彈出菜單屬於框架窗口的時候(可在TrackPopupMenu函數參數中設置),彈出菜單上的消息,在路由的時候,仍然遵循View-DOC-MainFrame-APP的響應順序。

 

10. 動態菜單編程

所有的資源對象都有一個數據成員保存了資源的句柄。

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. 手動給動態菜單項添加響應函數

      在Resource.h中可以添加資源的ID;在頭文件中寫消息函數原型;在代碼文件中添加消息映射和添加消息響應函數

說明:

可以先創建一個臨時的菜單項,設置它的ID和動態菜單項的一致,然後對它用嚮導進行消息響應,然後刪除臨時菜單。

再在代碼文件中把消息映射放到宏外(注意一定要放到宏外面,因爲CLASSWIZARD發現菜單刪除了,同時要把其宏對裏的消息映射也刪除掉的)

 

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 //注意其參數的作用

 

13. 集合類

CStringArrayCDWordArrayCPtrArrayCUIntArrayCWordArray

 

14. 命令消息是到OnCommand函數的時候完成路由的

由於CWnd::OnCommand 是個虛函數,可以在框架類中重寫OnCommand函數,從而可以截獲菜單消息使它不再往下(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();//獲取當前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; 
      //函數返回,避免調用CFrameWnd::OnCommand函數,在CFrameWnd::OnCommand中截獲的消息會交由VIEW類處理
    }
   return CFrameWnd::OnCommand(wParam, lParam);
   //調用基類OnCommand函數,在CFrameWnd::OnCommand中截獲的消息會交由VIEW類處理
}

15. LOWORDHIWORD

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;//獲取當前視窗口指針(單文檔框架中)

源文件是單獨參與編譯的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章