Win32的菜單編程

 

 
WIN32用戶界面設計基礎之Menus篇
 
2003-3-29 13:05:28   YESKY   陳孝強   閱讀次數: 4835
 
一個菜單條總是屬於一個窗口,當用戶選定一個菜單項後,系統向菜單的父窗口發出消息,如果是普通菜單發送WM_COMMAND消息,如果是系統菜單發送WM_SYSCOMMAND消息。當鼠標懸浮在一個有下級菜單的菜單項上時,系統首先向菜單的父窗口發送WM_INITMENUPOPUP消息,然後展開子菜單。每一個菜單條由一個唯一的句柄指向,類型爲HMENU。獲得一個菜單的句柄使用GetMenu()函數,獲得子菜單用GetSubMenu()、GetMenuItemInfo()。獲得窗口的系統菜單句柄應當使用GetSystemMenu()。菜單除了句柄,還有ID,類似於按鈕的ID,當菜單觸發事件時,菜單ID被包含在WM_COMMAND或WM_SYSCOMMAND中一同發送。可以通過GetMenuItemID()獲取一個菜單項的ID。訪問菜單項時如果使用ID的方式會比較麻煩,一種變通的方法就是按照菜單項的以0爲基數的索引進行訪問,最左邊的爲0,向右逐次遞增,最上邊的爲0,向下逐次遞增。
 
  一、 菜單的建立
 
  1、 使用菜單資源
 
  首先設計好菜單,然後用LoadMenu()加載,再用SetMenu()設置,例如,在窗口的WM_CREATE消息中:
 
HMENU hMenu;
hMenu=LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));
SetMenu(hWNd,hMenu);
 
  2、 內存菜單模板建立菜單
 
  有的應用程序允許用戶自定義菜單,這就要求使用內存菜單模板來定義菜單,然後用LoadMenuIndirect()函數加載這個內存菜單模板獲得菜單句柄,內存菜單模板由兩部分組成:一個MENUITEMTEMPLATEHEADER(或者MENUEX_TEMPLATE_HEADER)結構和若干個MENUITEMTEMPLATE(或者MENUEX_TEMPLATE_ITEM)結構
 
  3、 CreateMenu()函數
 
  CreateMenu()函數返回一個指向空菜單的HMENU指針,利用這個指針向其中添加菜單項InsertMenuItem()。 動態菜單創建後必須調用SetMenu()函數
 
  二、 菜單的顯示
 
  1、 對於已經通過在WNDCLASSEX窗口類註冊時指定hMenu成員或者調用SetMenu()函數爲其設定了父窗口的菜單,窗口顯示,菜單自動顯示
 
  2、 顯示彈出菜單應使用TrackPopmenuEx()函數,例如
 
HMENU hpMemu;
hpMenu=LoadMenu(hInst,MAKEINTRESOURCE(IDR_POPMENU);
TrackePopmenuEx(
hpMenu,//菜單的句柄
TPM_LEFTALIGN,//菜單和彈出點座標的對齊方式
x,//彈出點X座標
y,//彈出點Y座標
hWnd,//父窗口句柄
NULL);
 
  3、 菜單顯示過程中的消息
 
  用戶單擊菜單欄上的一項,父窗口接收到WM_INITITEM消息(在這個消息中可以繪製菜單),然後彈出菜單。當鼠標指向一個可以彈出子菜單的菜單項時,父窗口接收到WM_INITMENUPOPUP(可捕獲此消息繪製子菜單),然後彈出子菜單。當鼠標在菜單上移動時,父窗口接收到WM_MENUSELECT消息,該消息中包含有當前的菜單項的索引號,可以對其進行引用。單擊一個菜單項,產生WM_COMMAND消息,單擊一個風格爲MNS_NOTIFYBYPOS的菜單項,產生WM_MENUCOMMAND消息,該消息除了提供WM_COMMAND消息提供的數據外還額外添加了一個MENUINFO結構。右鍵彈出菜單發送WM_CONTEXTMENU消息。用戶在一個菜單項上右擊鼠標將產生WM_MENURBUTTONUP消息(例如在IE的收藏菜單的菜單項上右擊彈出菜單的效果就可以通過捕獲該消息實現)
三、 菜單的動態更改
 
  1、 插入新的菜單項InsertMenuItem()
 
  首先填寫MENUINFO結構
 
typedef struct tagMENUITEMINFO {
UINT cbSize; 結構的大小,sizeof(MENUINFO)
NT fMask; 將要獲得或者設置的項目,後面的哪些參數發揮作用受該參數的設置的影響。MIIM_BITMAP,hbmpItem將用來設置或返回按鈕的位圖,MIIM_ID,wID設置或返回菜單項的ID
UINT fType; 設置或返回菜單項的類型,MFT_BITMAP位圖;MFT_STRING字符串;MFT_OWNERDRAW,發送WM_DRAWITEM和WM_MEASUREITEM消息用於繪製菜單項
UINT fState; 菜單項的狀態:MFS_DEFAULT,默認;MFS_GRAYED,不可用;
UINT wID; 菜單項的ID,要求fMask中有MIIM_ID
HMENU hSubMenu; 下一級菜單的句柄,要求fMask中有MIIM_SUBMENU
HBITMAP hbmpChecked;
HBITMAP hbmpUnchecked;
ULONG_PTR dwItemData;
LPTSTR dwTypeData;
UINT cch;
HBITMAP hbmpItem;
} MENUITEMINFO, *LPMENUITEMINFO;
然後調用InsertMenu()函數
InsertMenu(
HMENU hMenu;
UINT nItems;
BOOL isPisition;//設爲TRUE,nItems爲菜單項的索引號,設爲FALSE,nItems爲菜單項的ID
LPCMENUITEMINFO lpmiinfo;
)
 
  2、 修改菜單項屬性使用SetMenuItemInfo()函數
 
  3、 刪除菜單項
 
    DeleteMenu()和RemoveMenu(),菜單項刪除後用DrawMenuBar()重繪菜單顯示更新
 
  四、 菜單特效
 
  1、 快捷菜單
 
  捕獲父窗口的WM_CONTEXTMENU(用戶在窗口中右擊鼠標將激活該事件),調用函數
TrackPopupMenuEx();TrackPopupMenuEx(hm,
0,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),hWnd,NULL);hm爲菜單句柄,GET_X_LPARAM(不知怎麼不能用)宏獲得事件發生時鼠標的X座標,hWnd爲父窗口句柄
 
  2、 位圖菜單
 
    MENUITEMINFO結構的fMask中添加MIIM_BITMAP標誌,爲期hbmItem指定一個指向位圖的指針
 
  五、 自繪製菜單
 
  1、 指定標誌
 
  要實現自繪製必須使菜單項的風格符合要求,有兩種方法可以做到,其一是用InsertMenuItem()函數插入,其二是用SetMenuItemInfo()函數修改,不論使用哪一個都必須填寫一個MENUITEMINFO結構,爲其fMask添加MIIM_FTYPE,爲其fType添加MFT_OWNERDRAW。和列表框一樣,對菜單項進行自繪製是設計到較多的數據傳遞,可以存放在MENUITEMINFO結構中,設置fMask爲MIIM_DATA,然後給dwItemData成員賦值。WM_DRAWITEM(LPDRAWITEMSTRUCT)和WM_MEASUREITEM(LPMEASUREITEMSTRUCT)的參數中都含有itemData成語用於取出預先存放的數據。
 
  例如:
 
MENUITEMINFO mi;
HMENU hmn;
mi.fMask=MIIM_FTYPE;
milfType=MFT_OWNERDRAW;
hmn=GetMenu(hWnd);
SetMenuItemInfo(hmn,0,TRUE,&mi);
 
  2、 處理WM_MEASUREITEM消息
 
  用戶單擊,菜單即將顯示時,菜單的父窗口接收到WM_MEASUREITEM消息,捕獲此消息可以設置菜單項的尺寸,例如:
 
LPMEASUREITEMSTRUCT lpmis;
lpmis=(LPMEASUREITEMSTRUCT)lParam;
lpmis->itemHeight=48
lpmis->itemWidth=144;
 
  3、 處理WM_DRAWITEM消息
 
  WM_DRAWITEM消息的LPARAM參數爲一個LPDRAWITEMSTRUCT指針,其中含有指向被繪製的菜單項的設備場景指針、菜單ID和狀態等信息,根據這些信息進行繪製,例如:
 
LPDRAWITEMSTRUCT lpdis;
HDC hMem;
HBITMAP hbm;
hMem=CreateCompatibleDC(lpdis->hDC);
hbm=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_MENUMAP));
SelectObject(hMem,hbm);
BitBlt(lpdis->hDC,0,0,lpids->rcItem.right,lpdis->rcItem.bottom,hMem,0,0,SRCCOPY); 
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章