程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何定制對話框系統菜單

如何定制對話框系統菜單

編輯:關於VC++

背景

系統菜單是每個 Windows 程序的標准特性。通常系統菜單由 Windows 系統來管理,所以我們平時編成時很少去碰它。但是,有的時候,我們確實想定制自己的系統菜單項。這樣就涉及到定制菜單的處理問題,因為 Windows 無法自動處理我們定制的系統菜單。而且,系統菜單的處理方式與常規的菜單處理是不同的。那麼我們如何實現定制的系統菜單呢?相信看完本文的介紹,你會得到滿意的答案。

本文例子是一個典型的C++/MFC對話框程序,設置了 EX_WM_TOOLWINDOW 擴展式樣,因此在標題欄左上角看不到系統菜單圖標,但通過 Ctrl+Space 或者在標題欄單擊鼠標右鍵可以調出系統菜單。例子程序對系統菜單進行了定制,在原有菜單基礎上添加了兩個菜單命令:一個是顯示“關於”對話框;另一個是“退出”。之所以要加一個“退出”菜單命令,是因為例子程序改寫了對話框原來默認的“關閉”菜單命令行為(Alt-F4),用來隱藏對話框。因此必須加一個程序的“退出”出口。此外,例子程序利用一個第三方的系統托盤處理類,利用系統托盤圖標可以顯示/隱藏對話框。 下面我們就來看看用 C++/MFC 實現的細節。

添加菜單

首先在資源定義文件 resource.h 中定義菜單項標示,也可以在標准頭文件中定義。菜單項標示必須具有唯一性。其次,Windows 對系統菜單的處理與常規菜單的處理方法是不同的,不管是缺省的菜單還是定制的菜單,它們都沒有象常規菜單命令那樣的消息處理例程。假設我們要添加兩個定制的系統單:

#define IDM_ABOUT 16
#define IDM_EXIT 17

IDM_的意思是該定義為菜單項ID。添加菜單命令是在對話框的初始化例程以及窗口創建函數(OnInitDialog(), OnCreate())中進行的。如:BOOL CBabelOnDlg::OnInitDialog()
{
  CDialog::OnInitDialog();
// 在系統菜單中添加 "關於..." 和 "退出" 菜單項
// 解決 Windows 95 中的 bug
  ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
// 命令 IDs 必須在預定義的系統菜單之後
  ASSERT(IDM_ABOUTBOX < 0xF000);
// 解決 Windows 95 中的 bug
  ASSERT((IDM_EXIT & 0xFFF0) == IDM_EXIT);
// 命令 IDs 必須在預定義的系統菜單之後
  ASSERT(IDM_EXIT < 0xF000);
  CMenu* pSysMenu = GetSystemMenu(FALSE);
  if (pSysMenu != NULL)
  {
   pSysMenu->AppendMenu(MF_STRING,IDM_EXIT,"退出(&x)");
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, "關於(&A)...");
   ......
  }
  ......
  //other initialization
}

這裡在添加每個菜單前都有兩個 ASSERT 語句,第一個 ASSERT 的目的是修復 Windows 95 中存在的 Bug,第二個 ASSERT 保證定制的命令 IDs 是在預定義的系統菜單之後,以免發生沖突。查一下 MSDN 庫的 MFC 文檔關於系統菜單的描述,你會發現下面的內容:“......所有預定義的控制菜單項(也就是系統菜單)的ID號必須大於 0xF000。如果某個應用程序要添加系統菜單,其系統菜單的 ID 號必須小於F000。”

接下來,用 GetSystemMenu 函數獲取系統菜單指針。調用時使用參數 FALSE 獲取指針。如果用 TRUE 作為參數,那麼該函數會將菜單重置回缺省狀態。

如果得到的指針有效,接著調用菜單添加命令在系統菜單後面添加菜單項,傳遞菜單IDs以及菜單顯示時所用的字符串。

處理定制的菜單命令

為了讓這些系統菜單命令工作起來,我們不能依賴常規的菜單消息處理機制----即便菜單項相同。通常系統菜單通過 WM_SYSCOMMAND 消息處理:

void CBabelOnDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
  //trap our own system menu messages
  if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  {
    CAboutDlg dlgAbout;
  dlgAbout.DoModal();
  } else if ((nID & 0xFFF0)==SC_CLOSE){
  OnClose();
  } else if ((nID & 0xFFF0)==IDM_EXIT) {
  ::PostQuitMessage(0);
  }
  else {
      CDialog::OnSysCommand(nID, lParam);
  }
}

通過比較傳入的菜單ID進行相應的處理。注意代碼中又有兩個“nID & 0xFFF0”,這主要也是解決 Windows 95 的 bug。如果選擇“退出”,那麼會向應用程序發送退出消息:::PostQuitMessage(0)。

注意第二個條件檢查:SC_CLOSE 是個預定義的菜單常量。一般它是由 Windows 處理的,因為在例子程序中我們對它進行了定制,所以必須要自己處理它。本來 SC_CLOSE 是退出程序,但例子程序我們把它的行為改寫成隱藏對話框,也就是將應用變成一個托盤小圖標,處理例程見 OnClose() 函數。如果傳入的菜單ID不等於任何定制的菜單項,那麼就讓 Windows 對它進行默認處理:CDialog::OnSysCommand(nID, lParam);下面是幾個最常用的系統菜單命令:

菜單 說明 SC_CLOSE 關閉 CWnd 對象 SC_MAXIMIZE 或者 SC_ZOOM 最大化 CWnd 對象 SC_MINIMIZE 或者 SC_ICON 最小化 CWnd 對象 SC_MOVE 移動 CWnd 對象 SC_RESTORE 恢復窗口的正常位置和大小 SC_SIZE 改變 CWnd 對象大小

其它的幾個系統菜單命令一般都是在特殊情況下才使用,有關細節請參考有關 WM_SYSCOMMAND 的文檔。

修改現有的菜單命令

我們已經看到,系統菜單本身默認的處理行為是可以改變的,除此之外,系統菜單項的描述文本也是可以改變的,甚至還可以刪除它們。為了修改才單命令的描述文本,我們可以用 pSysMenu 指針調用 ModifyMenu() 函數。例如,如果想要把“關閉”菜單項改成“隱藏”,可以象下面這麼做:

pSysMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND,IDM_HIDE, "隱藏(&H)");

MF_BYCOMMAND 參數告訴該函數將 SC_CLOSE 解釋為命令 ID。IDM_HIDE 是新的菜單 ID。最後一個參數是菜單項的說明文本。還有一種調用 ModifyMenu() 的方法是使用 菜單項索引作為參數:

pSysMenu->ModifyMenu(0,MF_BYPOSITION,IDM_HIDE,"隱藏(&H)");

第一個參數 0 表示菜單項的索引,指第一個菜單。

刪除菜單命令

例子程序擬將去掉系統菜單中的窗口“關閉”命令,暫且不說這樣做是否合適,但是我們能做到這一點:

pSysMenu->RemoveMenu(SC_CLOSE,MF_BYCOMMMAND);
   pSysMenu->RemoveMenu(0,MF_BYPOSITION);

第一行代碼刪除了與 SC_CLOSE 關聯的菜單命令。而第二行代碼表示刪除系統菜單命令中的第一項。

用這種方式修改系統菜單盡管限定了應用程序的某些行為,但對於小型應用和實用程序來說有時是很有用的,尤其是當你想要從任務欄存取菜單命令時----也就是程序在後台運行或者以最小化方式運行,右鍵單擊任務欄圖標將彈出系統菜單。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved