孫鑫視頻教程第六課——菜單

來源:互聯網
上載者:User

        孫鑫視頻教程第六課的主要內容是:介紹如何從靜態方面和動態方面去建立一個功能表列,對功能表列的各項修改!菜單的工作原理及編寫應用,功能表命令訊息在MFC架構程式的幾個類中的行程順序和處理過程。標記菜單、預設菜單的實現原理、圖形菜單的實現及常犯錯誤的分析,GetSystemMetrics的應用,快捷快顯功能表的實現方式及其命令響應函數有效範圍(與快顯功能表時所指定的父視窗有密切的關係,最底層的子視窗具有最優先的處理機會)。動態菜單的編寫,如何讓程式在運行時產生新的功能表項目及如何手工為這些新產生的功能表命令安排處理函數,如何在頂層視窗中截獲對功能表命令的處理,更進一步掌握CString類的應用。

1.訊息的分類與響應:

標準訊息       除WM_COMMAND之外,所有以WM_開頭的訊息。       從CWnd派生的類,都可以接收到這類訊息。 命令訊息       來自菜單、加速鍵或工具列按鈕的訊息。這類訊息都以WM_COMMAND呈現。在MFC中,通過功能表項目的標識(ID)來區分不同的命令訊息;在SDK中,通過訊息的wParam參數識別。從CCmdTarget派生的類,都可以接收到這類訊息。 通告訊息       由控制項產生的訊息,例如,按鈕的單擊,列表框的選擇等均產生此類訊息,為的是向其父視窗(通常是對話方塊)通知事件的發生。這類訊息也是以WM_COMMAND形式呈現。從CCmdTarget派生的類,都可以接收到這類訊息。 下面來講解我們執行個體的訊息響應原理:訊息轉到OnCommand時,由cmainframe類接收轉給cview類,如果cview類中有響應函數就響應,如果沒有就交給cdoc類,如果cdoc類有響應函數就響應,如果沒有就交回給cview類,再由cview類交給cmainframe類,如果cmainframe類中有響應函數就響應,如果沒有就由cmainframe類交給capp類響應!所以整個響應函數的順序為:Cview類—>CMainframe類—>CDoc類—>CApp類!(PS:快顯視窗不能進行訊息響應的,所以我們需要在Menu中的屬性中將popup這個欄目的勾踢掉!)
2.a.如何建立標記菜單:要想很好很容易的建立標記菜單,我們需要對菜單有一個比較熟悉的瞭解!可以看看下 圖:  
在這裡建立一個標記菜單需要的函數有:GetMenu()返回一個指向功能表列的指標,GetSubMenu()返回一個指向子功能表的指標,還有CheckMenuItem()!建立語句如下:在Cmainframe()的OnCreate()函數中添加如下代碼:GetMenu()->GetSubMenu(0)->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);//按索引號來訪問GetMenu()->GetSubMenu(0)->CheckMenuItem(IDM_TEST, MF_BYCOMMAND | MF_CHECKED);//按ID號訪問!b.建立預設功能表項目:(注意在一個子功能表中只可以建立一個預設的功能表項目,而且需要注意索引號的擷取,要加上分隔字元的索引號數)GetMenu()->GetSubMenu(0)->SetDefaultItem(1, TRUE);GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN);c.建立圖形標記功能表項目:(在vs2008中與vc6.0中有區別:在vs2008中可以不用擷取系統度量函數,而在vc6.0中需要使用到這個函數GetSystemMetrics())m_bitmap1.LoadBitmapW(IDB_BITMAP1);
 GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bitmap1, &m_bitmap1);d.讓功能表項目不可使用:這個功能可以通過使用屬性中的選項輕鬆實現,但是使用代碼需要注意:你需要在cmainframe函數的建構函式中將m_bAutoMenuEnable變數設定為false,下面的代碼才會生效,GetMenu()->GetSubMenu(0)->EnableMenuItem(1, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);但是在你將m_bAutoMenuEnable變數設定為false之後,會有另一個問題的產生:原來不可以使用的功能表項目變為了可用了,這可以使用f中的方法!e.如何將整個菜單取消:可以直接用函數SetMenu(NULL);下面的代碼是又講菜單調用出來的,不過有一點是需要注意的!CMenu menu;//當這個變數為局部變數的時候,就需要加上menu.Detach()這個函數將該變數與c++對象斷開,這樣就不會發生析構了!
 menu.LoadMenuW(IDR_MAINFRAME);
 SetMenu(&menu);
 menu.Detach();f.命令更新機制:       功能表項目狀態的維護是依賴於CN_UPDATE_COMMAND_UI訊息,誰捕獲CN_UPDATE_COMMAND_UI訊息,MFC就在其中建立一個CCmdUI對象。我們可以通過手工或利用ClassWizard在訊息映射中添加ON_UPDATE_COMMAND_UI宏來捕獲CN_UPDATE_COMMAND_UI訊息。        在後台所做的工作是:作業系統發出WM_INITMENUPOPUP訊息,然後由MFC的基類如CFrameWnd接管。它建立一個CCmdUI對象,並與第一個功能表項目相關聯,調用對象的一個成員函數DoUpdate()。這個函數發出CN_UPDATE_COMMAND_UI訊息,這條訊息帶有指向CCmdUI對象的指標。同一個CCmdUI對象就設定為與第二個功能表項目相關聯,這樣順序進行,直到完成所有功能表項目。        更新命令UI處理常式僅應用於彈出式功能表項目上的項目,不能應用於永久顯示的頂級功能表項目。這樣就可以在不可以使用的功能表項目上添加一個訊息處理常式即可!如下例:void CMainFrame::OnUpdateEditCut(CCmdUI *pCmdUI)
{
 // TODO: 在此添加命令更新使用者介面處理常式代碼
 pCmdUI->Enable();
}這樣剪下的功能表項目就可以使用了!g.在view類中右鍵快顯功能表功能的實現:在vs2008中,不可以象vc6.0那樣可以手動的添加一個快顯功能表功能,所以就需要我們手動的寫代碼來實現,在view類中添加一個訊息響應函數OnRButtonDown(),還需要添加一個menu資源,代碼如下:CMenu menu;
 menu.LoadMenuW(IDR_MENU1);
 CMenu *Popup = menu.GetSubMenu(0);
 ClientToScreen(&point);//由客戶區的座標轉換為螢幕座標!
 Popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);//建立一個快顯功能表上面的代碼就可以實現在視圖類中點擊右鍵快顯功能表的功能!
3.下面主要介紹的是動態添加菜單:
動態添加菜單需要用到的函數主要有:Createpopmenu(), AppenMenu(),InsertMenu(),DeleteMenu(),這裡要區別各個函數的主要功能,不要搞錯!第一個函數主要建立一個空的菜單,第二個函數主要是在功能表列的後面添加菜單,但是在不同的地方,它的功能就會不同,在下面的代碼中可以看到,第三個函數的功能主要是在兩個菜單之間添加自己需要的菜單!第四個函數是刪除一個菜單!他們的實現在不同的地方就有不同的用處,具體的實現看如下代碼:在cmainframe()類的oncreate()函數中實現CMenu menu;
 menu.CreatePopupMenu();
 //GetMenu()->AppendMenuW(MF_POPUP, (UINT)menu.m_hMenu, TEXT("WinSun"));//在現有的菜單後面添加菜單
 GetMenu()->InsertMenuW(2, MF_BYPOSITION | MF_POPUP, (UINT)menu.m_hMenu, TEXT("WinSun"));//在現有的菜單之間插入一個菜單!
 menu.AppendMenuW(MF_STRING, 111, TEXT("Hello"));//添加功能表項目
 menu.AppendMenuW(MF_STRING, 112, TEXT("WinSun"));
 menu.AppendMenuW(MF_STRING, 113, TEXT("Mybloe"));
 menu.Detach();GetMenu()->GetSubMenu(0)->AppendMenuW(MF_STRING, 114, TEXT("welcome"));//在子功能表中添加功能表項目
 GetMenu()->GetSubMenu(0)->InsertMenuW(2, MF_BYPOSITION | MF_STRING, 115, TEXT("維新"));//在子功能表中插入功能表項目!
 GetMenu()->DeleteMenu(1, MF_BYPOSITION);//刪除菜單
 GetMenu()->GetSubMenu(0)->DeleteMenu(1, MF_BYPOSITION);//刪除功能表項目!
4.編寫電話本程式:
這個電話本的功能主要是:當在view類的視窗上寫入一個人的姓名和電話號碼,就自己添加姓名到功能表列上面去,然後當我要點擊功能表列上的子功能表的功能表項目的時候,這個人的姓名和電話號碼又顯示在我們的view類上面,實現的代碼如下:

void CID063View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)//在view類中添加一個訊息響應函數!
{
 // TODO: 在此添加訊息處理常式代碼和/或調用預設值
 CClientDC dc(this);
 if (0x0d == nChar)
 {
  if (0 == ++m_nIndex)
  {
   m_menu.CreatePopupMenu();
   GetParent()->GetMenu()->AppendMenuW(MF_POPUP, (UINT)m_menu.m_hMenu, TEXT("PhoneBook"));//首先得到父類的指標,再由父類的指標指向子類
   GetParent()->DrawMenuBar();//讓功能表列發生重繪!這樣我們在view類中建立的菜單才可以顯示出來!
  }
  m_menu.AppendMenuW(MF_STRING, IDM_PHONE1+m_nIndex, m_strLine.Left(m_strLine.Find(' ')));
  m_strArray.Add(m_strLine);//將輸入的字串添加到集合類中儲存起來!
  m_strLine.Empty();//清Null 字元串
  Invalidate();//讓整個視窗用戶端地區無效!
 }
 else
 {
  m_strLine += (TCHAR)nChar;
  dc.TextOutW(0, 0, m_strLine);
 }

 CView::OnChar(nChar, nRepCnt, nFlags);
}

void CID063View::OnPhone1()//這個是動態添加功能表項目的響應函數!
{
 // TODO: 在此添加命令處理常式代碼
 CClientDC dc(this);
 dc.TextOutW(0, 0, m_strArray.GetAt(1));
}

void CID063View::OnPhone2()
{
 // TODO: 在此添加命令處理常式代碼
 CClientDC dc(this);
 dc.TextOutW(0, 0, m_strArray.GetAt(2));
}

void CID063View::OnPhone3()
{
 // TODO: 在此添加命令處理常式代碼
 CClientDC dc(this);
 dc.TextOutW(0, 0, m_strArray.GetAt(3));
}

void CID063View::OnPhone4()
{
 // TODO: 在此添加命令處理常式代碼
 CClientDC dc(this);
 dc.TextOutW(0, 0, m_strArray.GetAt(4));
}

下面的代碼是將cview類的訊息響應路徑的截斷,由cmainframe類來響應,要注意其標頭檔的包含:

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
 // TODO: 在此添加專用代碼和/或調用基類
 int MenuCmdId = LOWORD(wParam);//只需要擷取一個位元組的低位元組序就可以
 CID063View *pView = (CID063View*) GetActiveView();//擷取當前視類的指標
 if (MenuCmdId >= IDM_PHONE1 && MenuCmdId < IDM_PHONE1 + pView->m_strArray.GetSize())
 {
  CClientDC dc(pView);
  dc.TextOutW(0, 0, pView->m_strArray.GetAt(MenuCmdId - IDM_PHONE1));
  return TRUE;
 }

 return CFrameWnd::OnCommand(wParam, lParam);
}

(在vs2008中添加虛函數的方法:在你所需要的類上點擊右鍵,然後選擇屬性中的重寫就可以!)

 

以上的內容就是孫鑫第六課的主要知識點回顧!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.