1. 程式人生 > >MFC介面程式設計基礎(09):選單(二)

MFC介面程式設計基礎(09):選單(二)

上一篇:MFC介面程式設計基礎(08):選單(一) 下一篇:MFC介面程式設計基礎(10):基於對話方塊的MFC應用程式

快捷選單

我們平時在使用程式時,經常會用到單擊滑鼠右鍵顯示快捷選單(也稱上下文選單,右鍵選單)這一功能。如果想要自己實現這個功能,需要通過以下步驟來完成:

1.為程式新增一個新的選單資源。

可在【資源檢視】選項卡上的Menu分支上單擊滑鼠右鍵,從彈出的選單中選擇【新增資源】選單命令
在這裡插入圖片描述
在這裡插入圖片描述
這時,在Menu分支下就多了一個名為IDR_MENU1的選單資源,並同時在VS開發介面視窗的右邊視窗中打開了這個選單資源。接著就要為這個選單資源新增選單項了。因為在顯示快捷選單時頂級選單是不出現的,所以可以給它設定任意的文字。
2.給檢視類新增WM_RBUTTONDOWN訊息響應函式。


我們可以使用TrackPopupMenu函式來顯示一個快捷選單。該函式宣告形式如下:
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd,
LPCRECT lpRect = NULL );

引數:

  • nFlags 指定螢幕位置標誌或滑鼠鍵標誌。

螢幕位置標誌可以為下列值之一:

  • TPM_CENTERALIGN 使彈出選單在水平方向相對於x指定的座標居中。
  • TPM_LEFTALIGN 放置彈出選單,以便彈出選單在由座標值x指定的位置左對齊。
  • TPM_RIGHTALIGN 放置彈出選單,以便彈出選單在由座標值x指定的位置右對齊。

滑鼠鍵標誌可以為下列值之一:

  • TPM_LEFTBUTTON 導致彈出選單追蹤滑鼠左鍵。
  • TPM_RIGHTBUTTON 導致彈出選單追蹤滑鼠右鍵。
  • x 指定彈出選單螢幕座標的水平位置。根據引數nFlags的值,該選單可以左對齊、右對齊或在該位置上居中。
  • y 指定彈出選單螢幕座標的垂直位置
  • pWnd 標識擁有彈出選單的視窗。該視窗接收來自選單的所有WM_COMMAND訊息。在Windows 3.1或以後版本中,視窗直到TrackPopupMenu返回才接收WM_COMMAND訊息。在Windows 3.0中,視窗在TrackPopupMenu返回之前接收WM_COMMAND訊息。
  • lpRect 指向RECT結構或包含矩形的螢幕座標CRect物件,使用者在該矩形內部單擊滑鼠也不會消除彈出選單。若該引數為NULL ,那麼使用者在該矩形外部單擊滑鼠,彈出選單將消失。對於Windows 3.0,該值必須為NULL。

在這裡插入圖片描述

問題:
執行後發現這個快捷選單顯示的位置好像不太對,並不是在滑鼠右鍵單擊點處顯示的。這是因為TrackPopupMenu函式中的x和y引數都是螢幕座標,而滑鼠單擊點處的座標是視窗客戶區座標,即以程式視窗左上角為座標原點。

解決:
需要把客戶區座標轉換為螢幕座標。我們須在呼叫TrackPopupMenu函式之前呼叫ClientToScreen函式。函式原型如下:
void ClientToScreen( LPPOINT lpPoint ) const;
void ClientToScreen( LPRECT lpRect ) const;
引數:
lpPoint 指向一個POINT結構或CPoint物件,其中包含了要轉換的客戶區座標。
lpRect 指向一個RECT結構或CRect物件,其中包含了要轉換的客戶區座標。

在這裡插入圖片描述

3.為程式新增快捷選單上各選單項命令的響應函式。
在選單資源編輯器中,分別為CMainFrame類和CXXView類新增一個響應快捷選單項的函式,執行後你會發現是CXXView類中新增的響應在處理這個訊息。我們將CXXView類對快捷選單項命令訊息的響應函式刪除,再次執行,可是發現CMainFrame類對快捷選單命令訊息的響應函式還是沒有反應。這主要是因為在建立快捷選單時,即呼叫TrackPopupMenu函式時,對這個快捷選單的擁有者引數傳遞的是this值,也就是視類視窗擁有這個快捷選單。因此,只有視類才能對快捷選單項命令做出響應。如果想讓CMainFrame類能對這個快捷選單項進行響應的話,就應該在呼叫TrackPopupMenu函式時把快捷選單的擁有者指定為CMainFrame類視窗,為此我們可以修改CXXView類OnRButtonDown函式中隊TrackPopupMenu函式的呼叫,如下:
在這裡插入圖片描述
注意:
即便如此,框架類視窗能有機會獲得對該快捷選單中的選單項的命令響應,但最先響應還應是CXXView類視窗,除非CXXView類視窗沒有設定快捷選單的函式,才能由框架類視窗做出響應。這可由選單命令訊息路由的過程來解釋。

選單項動態操作

新增選單項

通過程式碼來動態地在已有選單專案後面新增新的選單項。
我們可以利用CMenu類提供的一個成員函式:AppendMenu來完成。該函式的作用是把一個新選單專案新增到一個指定選單專案的末尾。該函式具體宣告形式如下:
BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0,
LPCTSTR lpszNewItem = NULL );
引數:

  • nFlags
    指定了增加到選單中的新選單項狀態的有關資訊。它包括說明中列出的一個或多個值。下面列出的是nFlags可以設定的值:
    MF_CHECKED 該值的行為如同使用MF_UNCHECKED來作為一個標記,用於替換項前的檢測標記。若應用支援檢測標記點陣圖(請參閱SetMenuItemBitmaps成員函式),那麼將顯示“檢測標記開啟”點陣圖。

  • MF_UNCHECKED 該值的行為如同使用MF_CHECKED來作為一個標記,用於刪除項前的檢測標記。若應用支援檢測標記點陣圖(請參閱SetMenuItemBitmaps成員函式),那麼將顯示“檢測標記關閉”點陣圖。

  • MF_DISABLED 使選單項無效以便它不能被選擇,但選單項不變灰。

  • MF_ENABLED 使選單項有效以便它能夠被選擇,並從灰色狀態中恢復原樣。

  • MF_GRAYED 使選單項無效以便它不能被選擇,同時使選單項變灰。

  • MF_MENUBARBREAK 在靜態選單裡的新行中或彈出選單的新列中放置選單項。新的彈出選單列與老的選單列將由垂直分割線分開。

  • MF_MENUBREAK 在靜態選單裡的新行中或彈出選單的新列中放置選單項。列與列之間沒有分割線。

  • MF_OWNERDRAW 指定選單項為一個擁有者描繪的項。當選單首次顯示時,擁有該選單的視窗將接收WM_MEASUREITEM訊息,以獲取選單項的高度與寬度。WM_DRAWITEM訊息將使屬主視窗必須更新選單項的可視介面。該選擇項對於頂層選單項無效。

  • MF_POPUP 指定選單項有與之相關聯的彈出選單。引數ID指定了與項相關聯的彈出選單的控制代碼。它用於增加頂層彈出選單項或用於增加彈出選單項的下一級彈出選單。

  • MF_SEPARATOR 繪製一條水平的分割線。它僅僅能用於彈出選單項。該線不能變灰、無效或高亮度顯示。其它的引數將被忽略。

  • MF_STRING 指定選單項為一個字串。
    下面列出的各組標誌互相排斥,不能一起使用:

  • MF_DISABLED, MF_ENABLED,和 MF_GRAYED

  • MF_STRING, MF_OWNERDRAW, MF_SEPARATOR和點陣圖版本。

  • MF_MENUBARBREAK和MF_MENUBREAK

  • MF_CHECKED 和MF_UNCHECKED

  • nIDNewItem
    指定了新選單項的命令ID號,或如果nFlags被設定為MF_POPUP,該引數指定彈出選單的選單控制代碼(HMENU),否則就是新增新選單項的命令ID。如果nFlags被設定為MF_SEPARATOR,那麼引數NewItem將被忽略。

  • lpszNewItem
    lpszNewItem指定了新選單項的內容。引數nFlags以下列方式解釋lpszNewItem:
    在這裡插入圖片描述

插入選單項

通過程式碼來動態地在已有選單專案之間新增新的選單項。
我們可以利用CMenu類的InsertMenu成員函式來實現,該函式的宣告形式如下:
BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0,
LPCTSTR lpszNewItem = NULL );
引數:

  • nPosition
    指定將要插入的新選單項前的選單項。引數nFlags被用於以下列方式解釋:
    在這裡插入圖片描述
  • nFlags
    指定nPosition值如何被解釋,並指定要增加到選單中新選單項的狀態。對於能夠被設定的標誌,請參閱成員函式AppendMenu。如果需要指定多個值,需使用位與操作來組合MF_BYCOMMAND或MF_BYPOSITION標誌。
  • nIDNewItem
    指定新選單項的命令ID號,或者,若nFlags被設定為MF_POPUP,則指定為彈出選單的選單控制代碼(HMENU)。若nFlags被設定為MF_SEPARATOR,那麼引數nIDNewItem將被忽略。
  • lpszNewItem
    指定新選單項的文字。nFlags被用於以下列方式解釋lpszNewItem:

在這裡插入圖片描述

刪除選單項

CMenu提供一個DeleteMenu成員函式,函式宣告如下:
BOOL DeleteMenu( UINT nPosition, UINT nFlags );
引數:

  • nPosition
    指定由nFlags決定的將要刪除的選單項。
  • nFlags
    以下列方式解釋nPosition:

在這裡插入圖片描述

利用這個函式可以刪除一個選單專案,包括子選單,以及子選單下的選單項,主要取決於呼叫這個函式的物件,如果該物件是程式的選單欄物件,那麼刪除的就是指定的子選單;如果該物件是一個子選單物件,那麼刪除的就是該子選單的下一個選單項。

知識拓展:模擬動畫圖示

當我們的程式啟動之後,讓程式的圖示不斷的變化,給人一種動畫效果。

1.載入圖示資源

  • 在程式的【資源檢視】中匯入圖示資源:
    在這裡插入圖片描述
  • 在程式的CMainFrame類中,定義一個圖示控制代碼陣列成員變數,用來存放在資源檢視中新增的圖示的控制代碼:

private:
HICON m_hIcons[4];

  • 在CMainFrame類的OnCreate函式中利用LoadIcon載入新增的圖示資源:
    使用LoadIcon函式如果載入的是系統圖標第一個引數應該設定為NULL,如果需要使用自定義圖示,該函式的第一個引數應該設定為改程式當前的例項控制代碼。
    HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);

獲取當前程式例項控制代碼的方式:

①使用AfxGetInstanceHandle()函式
②使用全域性例項物件theApp訪問其資料成員m_hInstance
注意:在使用之前必須宣告這個變數是在外部定義的
extern CMyApp theApp
③使用全域性函式AfxGetApp()獲取當前應用程式指標,通過該指標來訪問應用程式的成員變數m_hInstance

	m_hIcons[0] = LoadIcon(AfxGetInstanceHandle(),
 MAKEINTRESOURCE(IDI_ICON1));
	m_hIcons[1] = LoadIcon(AfxGetInstanceHandle(),
 MAKEINTRESOURCE(IDI_ICON2));
	m_hIcons[2] = LoadIcon(AfxGetInstanceHandle(), 
MAKEINTRESOURCE(IDI_ICON3));
	    m_hIcons[3] = LoadIcon(AfxGetInstanceHandle(),
 MAKEINTRESOURCE(IDI_ICON4));

MAKEINTRESOURCE巨集:
將資源ID轉換為相應的資源識別符號字串

2.定時器處理

  • 在CMainFrame類的OnCreate函式中設定定時器:
    SetTimer(1, 1000, NULL);
  • 為CMainFrame類新增WM_TIMER訊息相應函式OnTimer
  • 在OnTimer函式中使用SetClassLong函式為應用程式設定自定義圖示
    函式原型如下:
DWORD SetClassLong(HWND hWnd,int nlndex,LONG dwNewLong)

引數:
hWnd:視窗控制代碼及間接給出的視窗所屬的類。
nIndex: 指定要設定的索引
GCL_HBRBACKGROUND 設定新的背景畫刷
GCL_HCURSOR 設定新的游標
GCL_HICON 設定新的圖示
GCL_STYLE 設定新的視窗樣式

void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
		// TODO:  在此新增訊息處理程式程式碼和/或呼叫預設值
		static int nIndex = 0;
		SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[nIndex]);
		nIndex = ++nIndex % 4;
		CFrameWnd::OnTimer(nIDEvent);
}
上一篇:MFC介面程式設計基礎(08):選單(一) 下一篇:MFC介面程式設計基礎(10):基於對話方塊的MFC應用程式