?? 06.3.7 快捷菜單.txt
字號:
6.3.7 快捷菜單
我們平時在使用程序時,經常會用到單擊鼠標右鍵顯示快捷菜單(也稱為上下文菜單,或右鍵菜單〉這一功能。現在我們的這個Menu程序還不具備這個功能,讀者可以試試在 Menu程序的窗口中單擊鼠標右鍵,會發現程序沒有任何反應。
要實現右鍵快捷菜單功能,讀者可能會覺得無從下手。實際上, VC++己經為我們實現了這個功能。我們可以在VC++開發界面中選擇【Project】菜單下的【Add To Project>,然后從它的下拉菜單中選擇【Components and Controls....】菜單項。如圖6.28所示。
圖 6.28添加已有組件或控件的菜單命令
這時會出現如圖 6.29所示的組件和控件庫對話框。這個組件和控件庫里的內容是 VC++己經為我們編寫好的一些功能,就是一些組件和 ActiveX控件,可以供我們方便地直接調用它們。
在圖6.29所示的對話框中,雙擊Visual C++ Components目錄,從而打開這個目錄,該目錄下的內容如圖 6.30所示。其中,可以看到有一個名稱為 "Pop-upMenu"的組件,這個組件的作用就是給一個派生于CWnd類的窗口添加一個右鍵菜單。選中此工頁,然后單擊【Insert】按鈕,系統會提示用戶是否確認當前的插入操作,單擊【確定】按鈕,確認此操作即可。這時就會出現如圖6.31所示的添加右鍵菜單設置對話框。
圖 6.29 Components and Controls Gallery對話框 圖 6.30 Visual C++提供的組件
通過如圖6.31所示的這個對話框,可以設置新添加的這個彈出菜單將添加到哪個窗口上,即圖6.31中的Add pop-up menu to下拉列表框中顯示的那個類。這里,不應該選擇 CMainFrame類,因為前面己經介紹過了,視類窗口始終是覆蓋在框架窗口之上的,框架窗口接收不到鼠標消息,而右鍵菜單是在鼠標右鍵單擊時產生的,而在框架窗口中又捕獲不到鼠標右鍵單擊這一消息,也就無法顯示快捷菜單。所以,這里應該選擇 CMenuView類。在Menu resource ID編輯框中顯示的是快捷菜單的資源ID,我們可以在這里修改這個標識,也可以以后再修改。本例中保持默認標識不變,然后單擊【OK】按鈕,即可返回到圖6.30所示的窗口界面,單擊【Close】按鈕,結束組件的添加。
Build并運行Menu程序,然后在程序的窗口中單擊鼠標右鍵,此時會出現一個快捷萊
‘~... I 189
第6
單。如圖6.32所示。
這時,在Menu這個工程中可以看到,在插入了這個Pop-upMenu組件后,添加了以下兩處內容:
第一處,在 ResourceView選項卡的Menu分支下多了一個標識為CGJDRYOPUP-MENU VIEW的菜單資源,這個菜單只有一個頂層菜單項: _POPUP_,其下有三個菜單項(如圖6.33所示),也就是如圖6.32所示的快捷菜單中的內容。
圖6.33添加Pop-upMenu組件后增加的快捷菜單資源
第二處,為CMenuView類添加了一個函數: OnContextMenu。在Menu程序運行時,當用鼠標右鍵單擊窗口時,程序就會調用這個函數。如例6-20所示代碼是VC++為我們添加的這個函數的源代碼。
f~tl6-20
void CMenuView : :OnContextMenu(CWnd會, CPoint poínt)
11 CG : This b10ck was added by the Pop-up Menu component
{
if (point .x -1 && point .y -1) {
Ilkeystroke invocation
CRect rect ;
GetClientRect(rect) ;
ClientToScreen(rect) ;
point = rect . TopLeft() ;
point .Offset(5 , 5) ;
CMenu nenu ;
VERIFY(rnenu . LoadMenu(CG_IDR_POPUP_MENU_VIEW)) ;
CMenu* pPopup = rnenu . GetSubMenu(O) ;
ASSERT(pPOpup != NULL);
CWnd* pWndPopupOwner = th工S ;
while (pWndPopupOwner->GetStyle() & WS_CHILD) pWndPopupOwner = pWndPopupOwner->GetParent();
pPopup->TrackPopupMenu(TPM_LEFTAL工 GN I TPM_RIGHTBUTTON , point . x , poìnt.y, pWndPopupOwner) ;
可以看到,這個函數內部調用了 TrackPopupMenu函數來顯示一個快捷菜單。后者具有以下形式的聲明:
BOOL TrackPopupMenu(UINT nFlags , int x , int y ,CWnd* pWnd, LPCRECT lpRect = NULL) ;
該函數的參數含義如下所述:
. nFlags
指定菜單在屏幕上顯示的位置。
. x和 y
分別指定快捷菜單顯示位置處的 x坐標和 y坐標。
. pWnd
指定快捷菜單的擁有者,也就是標識擁有快捷菜單的窗口對象。
. lpRect
指定一塊矩形區域。如果用戶在這個設定區域之內單擊鼠標,快捷菜單仍保持顯示:否則快捷菜單消失。如果這個參數的值是 NULL,當用戶在這個快捷菜單范圍之外其他地方單擊鼠標時,這個菜單就將消失。 lpRect參數的默認值是 NULL o
既然知道了 TrackPopupMenu這個函數就是用來顯示快捷菜單的,就可以在 Menu程序中實現自己的快捷菜單了。這可以通過以下幾個步驟來實現 :
E為 Menu程序增加一個新的菜單資源。可以在 ResourceView選項卡上的 Menu分支上單擊鼠標右鍵,從彈出的菜單中選擇【In sert Menu】菜單命令,這時,在 Menu分支下就多了一個名為 IDR MENUl的菜單資源,井同時在 VC++開發界面窗口的右邊窗口中打開了這個菜單資源。接著就要為這個菜單資源添加菜單項了。因為在顯示快捷菜單時頂級菜單是不出現的,所以可以給它設置任意的文本,例如 abc。接著,依次添加表 6.1中列出的兩個菜單項:
表 6.1需添加的菜單項
菜單項文本 菜單項標識
顯示 IDM SHOW
退出 IDM EXIT
回給 CMenuView類添加 WM RBUπONDOWN消息響應函數。如果是在鼠標右鍵單擊窗口時顯示快捷菜單,那么就應該捕獲這個消息。對于這個消息響應函數處理的內容可以參照剛才系統自動添加的 OnContextMenu函數,最后的實現代碼如例 6-21所示。
例 6-21
void CMenuView :: OnRButtonDown(U工 NT nFlags , CPoint point)
// TODO: Add your message handler code here and/or call default
CMenu menu;
menu.LoadMenu(IDR_MENU1) ;
CMenu* pPopup = menu.GetSubMenu( O) ;
pPopup->TrackPopupMenu(TPM_LEFTALIGN TPM_RIGHTBUTTON , point.x, point .y, this) ;
CView : :OnRButtonDown(nFlags , point);
在這個鼠標右鍵消息響應函數中,首先定義了一個 CMenu對象: menu,接著加載 C LoadMenu函數)菜單資源,并獲取該菜單的第一個子菜單(GetSubMenu函數)。對快捷菜單來說,實際上只有一個子菜單(位置索引為 0)。最后,調用 TrackPopupMenu函數顯示快捷菜單。
Build井運行 Menu程序,然后在該程序窗口中單擊鼠標右鍵,此時就會出現我們自定義的快捷菜單,如圖 6.34所示。
但是,這個快捷菜單顯示的位置好像不太對,并不是在鼠標右鍵單擊點處顯示的。這是因為 TrackPopupMenu函數中的 x和 y參數都是屏幕坐標,而鼠標單擊點處的坐標是窗口客戶區坐標,即以程序窗口左上角為坐標原點。圖 6.35顯示了窗口坐標和屏幕坐標的關系。
圖 6.34自定義的快捷菜單的顯示圖 6.35窗口坐標和屏幕坐標
這樣,就需要把客戶區坐標轉換為屏幕坐標。我們知道剛才利用OnContextMenu函數顯示快捷菜單時一切都是正常的,那么我們看看它的實現代碼 (例 6-20所示代碼),可以發現它調用了一個名為 ClientToScreen的函數。政函數的作用就是把客戶區坐標轉換為屏幕坐標,這正是我們所需要做的工作。于是修改例 6-21所示 CMenuView類的 OnRButtonDown函數,在調用TrackPopupMenu函數之前添加下面這行代碼完成坐標轉換:
ClientToScreen(&point) ;
再次Build并運行Menu程序,并在程序窗口中單擊鼠標右鍵,發現此時快捷菜單的顯示位置正常了,如圖6.36所示。
由為Menu程序添加快捷菜單上各菜單項命令的響應函數。可以在ResourceView選項卡上雙擊IDR_MENUl菜單資源,使其在資源編輯窗口中打開。然后在【顯示】菜單項上用單擊鼠標右鍵,從出現的快捷菜單中選擇【ClassWizard..】命令,這時會出現如圖6.37所示的對話框。該對話框詢問是否為IDR MENUl這個資源創建一個新類或者選擇一個己有類。可以不用對此做出處理,單擊【Cancel】按鈕取消此對話框即可。
圖 6.36正確的快捷菜單顯示圖 6.37 Adding a Class對話框
然后利用ClassWizard,分別為CMainFrame類和CMenuView類添加一個響應【顯示】菜單項(ID為10MSHOW)的函數(直接接受系統提供的默認函數名:OnShow),添加時,應在ClassWizard對話框中的Messages列表中選擇COMMAND消息。
接下來為新添加的消息處理函數添加代碼,在CMenuView類的 OnShow函數中添加如例6-22所示代碼中加灰顯示的那行代碼。
例6-22 void CMenuV工ew: : OnShow ( )
MessageBox ("View show");
在CMainFrame類的OnShow函數中添加例6-23所示代碼中加灰顯示的那行代碼。
例6-23
void CMainFrame: :OnShow()
MessageBox ("Main show"); ,
,
Build并運行 Menu程序,并在程序窗口中單擊鼠標右鍵,從出現的快捷菜單中選擇【顯示】菜單項,這時會彈出一個消息框,發現它顯示的信息是: View show,說明是視類響應了這個菜單命令消息。我們將 CMenuView類對【顯示】菜單命令消息的響應函數刪除,再次運行 Menu程序,并選擇快捷菜單中的【顯示】菜單項,可是,這時程序沒有任何反應。這主要是因為在創建快捷菜單時,即調用 TrackPopupMenu函數時,對這個快捷菜單的擁有者參數傳遞的是由is值,也就是視類窗口擁有這個快捷菜單。因此,只有視類才能對快捷菜單項命令做出響應。如果想讓 CMainFrame類能對這個快捷菜單項進行響應的話,就應該在調用 TrackPopupMenu函數時把快捷菜單的擁有者指定為 CMainFrame類窗口,為此,我們可以修改 CMenuView類 OnRB uttonDown函數中對 TrackPopupMenu函數的調用,結果如例 6-24所示。
19IJ6-24
void CMenuView : :OnRButtonDown(UINT nFlags , CPoint point)
CMenu menu ;
menu.LoadMenu(IDR_MENU1) ;
CMenu* pPopup = menu.GetSubMenu(O);
ClientToScreen(&point) ;
pPopup->TrackPopupMenu(TPM_LEFTAL工 GN I TPM_R工GHTBUTTON, point.x, point.y, Get Parent()};
CView : :OnRButtonDown(nFlags , point);
Build井運行 Menu程序,并在程序窗口中單擊鼠標右鍵,從出現的快捷菜單中選擇【顯示】菜單項,這時會彈出一個消息框,發現它顯示的信息是: Main show,這說明是框架類窗口響應了這個菜單命令消息。
這時,如果我們在視類中也添加了這個【顯示】菜單項的響應函數,那將會是誰做出響應呢?我們可以為 CMenuView類再次添加這個響應函數,并為其添加如例 6-22所示的代碼。然后 Build并運行 Menu程序,并選擇快捷菜單中的【顯示】菜單項,發現這時彈出的消息框中顯示的是: View show,說明是視類捕獲到了這個菜單命令。讀者可以根據本章前面講述的菜單命令消息路由的過程來解釋這個結果。
國際:對于快捷菜單,如果將其擁有者窗口設置為框架類窗口,則框架類
窗口才能有機會獲得對該快捷菜單中的菜單項的命令響應,否則,就只能由視
類窗口 f放出響應。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -