WIN 下的超動態菜單(一)簡介 WIN 下的超動態菜單(二)用法 作者:黃山松,發表於博客園:http://www.cnblogs.com/tomview/ auto_dynamenu 是一個動態生成WINDOWS菜單的c++封裝庫,設計思路是要儘量簡化動態菜單的生成代碼,在程式界面任何地方想要顯... ...
WIN 下的超動態菜單(二)用法
作者:黃山松,發表於博客園:http://www.cnblogs.com/tomview/
auto_dynamenu 是一個動態生成WINDOWS菜單的c++封裝庫,設計思路是要儘量簡化動態菜單的生成代碼,在程式界面任何地方想要顯示菜單(特別是右鍵菜單)的時候,可以方便生成菜單,特別可以根據程式當時的內部數據,內部狀態來生成不同的動態菜單。
auto_dynamenu 只封裝了一個靜態的介面函數,這樣處理的目的是把類的實現代碼可以放在頭文件的類的聲明裡面,這樣使用的時候只要包含頭文件就可以直接調用了,不需要把實現文件加入工程,簡化操作。
類的介面函數定義
/**************************************************************************************************\ * static int : 返回值,表明選擇了哪個菜單項或者被更新的 nDefaultValue * dynamenu : * HWND hWnd : 當前視窗句柄 * LPPOINT pPoint : 顯示菜單的位置,通常為0即可,自動確定顯示的菜單位置 * char* pszMenu : 表明動態菜單內容的菜單字元串 * int nDefaultMode : 自動更新菜單選擇標記的模式,0 無,1 等於模式,2 位模式 * int nDefaultValue : 預設值,根據這個值,按照 nDefaultMode 來顯示菜單項的選擇標記 \**************************************************************************************************/ class auto_dynamenu
{
public:
static int dynamenu(HWND hWnd, LPPOINT pPoint, char* pszMenu, int nDefaultMode, int nDefaultValue);
};
參數:pszMenu
介面用一個格式化的字元串 pszMenu 來表示動態菜單,具體格式規則如下:
(1)每個菜單項為一個以 \n 結束的字元串
(2)菜單項的字元串通常以等號 = 分割為兩部分,等號前面為要顯示的菜單內容,等號後面為選擇這個菜單後的取值
(3)菜單項的字元串裡面如果沒有等號,表明選擇菜單返回的時候,返回的是菜單項字元串
(3)每個菜單項字元串前面可以加如下的修飾符:
[a] *(星號):表示這個菜單項前面有點的選擇標記
[b] ^:表示這個菜單項前面有對勾的選擇標記
[c] #:表示這個菜單項是灰色的
[d] -(減號):表明這個菜單項和下一個菜單項之間分為不同的列(多列的菜單)
[e] `(鍵盤左上角的按鍵):表示一個沒有意義的占位符
[f] ~:表明是一個菜單分割線
(4)可以用單獨一行的 ~ 表示一個菜單分割橫線,“~\n”
(5)菜單項字元串等號前面部分的豎線字元”|“ 把菜單分割為父菜單和子菜單
(6)把不同的菜單項的字元串連接為一個完整的字元串就可以描述這個整個菜單了
例如:
char szMenu[] = "選項1=20\n" //選項1對應數值20,選擇這個函數返回20 "選項2=0x20\n" //選擇2對應數值0x20,選擇這個函數返回0x20 "選項3=0\n" //選項3對應數值0,選擇這個函數返回 INT_MAX(因為函數返回0代表沒有選擇菜單項,所以0用INT_MAX返回值表示) "~\n" //這個代表一個菜單分割橫線 "錄像|通用格式|avi格式=-1\n" //多級子菜單,選擇這個返回-1 "錄像|通用格式|~\n" //多級子菜單內部的分割橫線 "錄像|通用格式|mkv格式=-2\n" //多級子菜單,選擇這個返回-2 "錄像|~\n" "錄像|專用格式|rdv格式=-3\n" //多級子菜單,選擇這個返回-3 "~\n" "#暫停處理\n" //灰色禁用的菜單項,無法選擇,可以用於顯示信息 "~\n" "控制|^開始視頻=10\n" //顯示選中的視頻開始菜單,選擇返回10 "控制|結束視頻=11\n" //顯示沒有選中的菜單,選擇返回11 "播放當前錄像 1.avi=d:\\1.avi\n" //返迴文件名字元串指針 ;
上面的示例菜單字元串顯示出來的菜單如下:
參數:hWnd
雖然菜單的消息不發往任何視窗,但是這個必須指定一個有效的視窗句柄,否則菜單顯示不出來。通常指定對滑鼠右鍵響應要顯示菜單的視窗,或者主視窗。
參數:pPoint
菜單顯示位置坐標POINT的指針,用於指定菜單的顯示位置,是屏幕坐標。通常可以給0,這時程式自動選擇菜單的顯示位置,通常根據滑鼠當前位置的控制項類型確定,具體如下:
(1)如果是 BUTTON,工具欄上的按鈕,則顯示在這個控制項的下方,左側對齊
(2)如果是TreeView,ListView則顯示在當前滑鼠位置的條目的下方
(3)如果是TabCtrl則顯示在滑鼠當前的Tab頁的頁頭的下方
(4)大小像個按鈕的ActiveX控制項,顯示在下方
(5)其他顯示在滑鼠的當前位置
參數pPoint備註:
在這個參數給0的時候,代碼自動確定菜單顯示位置,但由於作者通常在VC6下編程(參見博文《我是如何把VC6一直用到2016年的》),因此代碼中判斷控制項類型用的 ClassName 沒有包含新版 Visual C 帶的控制項的類,可能需要使用者增加一些代碼中的控制項類名,對不同的控制項確定不同的顯示菜單的位置。具體情況參考文檔《WIN 下超動態菜單(三)代碼》。
參數:nDefaultMode
預設模式,如果為0,沒有預設模式,菜單項的標記都在菜單字元串中指定。
如果為1,相等模式,如果某個菜單項的取值等於傳入的nDefaultValue則顯示選中標記。
如果為2,為與模式,如果某個菜單項的取值與nDefaultValue的位與不為0,則顯示選中標記。
參數:nDefaultValue
當前的預設值,配合nDefaultValue使用。
返回值:
程式應該根據返回值來判斷選擇了哪個菜單,根據nDefaultMode不同含義有差別,用法也有差異。
(1)如果nDefaultMode為0
(a)返回值為0的時候,表明沒有選擇任何菜單選項;
(b)返回值為INT_MAX,表明選擇了某個值為0的菜單項;
(c)如果選擇的菜單項字元串裡面有等號,並且等號後面是數字(支持十進位和十六進位寫法),則返回這個數字;
(d)如果選擇的菜單項字元串裡面的等號後面是字元串,則返回這個等號後面的字元串的指針;
(e)如果選擇的菜單項字元串裡面沒有等號,則返回這個菜單項的字元串的指針。
(2)如果 nDefaultMode 為 1 或者 2
則返回nDefaultValue經過修改後的值,如果沒有選擇任何菜單,返回值等於nDefaultValue。
直接可以這樣寫 :
nDefaultValue = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, pszMenu, nDefaultMode/*1 or 2*/, nDefaultValue);
動態菜單顯示及根據返回值進行處理示例
char szMenu[] = "選項1=20\n" //選項1對應數值20,選擇這個函數返回20 "選項2=0x20\n" //選擇2對應數值0x20,選擇這個函數返回20 "選項3=0\n" //選項3對應數值0,選擇這個函數範圍 INT_MAX(因為函數返回0代表沒有選擇菜單項,所以0用INT_MAX返回值表示) "~\n" //這個代表一個菜單分割橫線 "錄像|通用格式|avi格式=-1\n" //多級子菜單,選擇這個返回-1,可以為負值 "錄像|通用格式|~\n" //多級子菜單內部的分割橫線 "錄像|通用格式|mkv格式=-2\n" //多級子菜單,選擇這個返回-2 "錄像|~\n" "錄像|專用格式|rdv格式=-3\n" //多級子菜單,選擇這個返回-3 "~\n" "#暫停處理\n" //灰色禁用的菜單項,無法選擇,可以用於顯示信息 "~\n" "控制|^開始視頻=10\n" //顯示選中的視頻開始菜單,選擇返回10 "控制|結束視頻=11\n" //顯示沒有選中的菜單,選擇返回11 "播放當前錄像 1.avi=d:\\1.avi\n" //返迴文件名字元串指針 ; int index = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 0, 0); switch (index) { case 0: //菜單沒有選擇,不做任何處理 break; case 20: //選項1 break; case 0x20: //選項2 break; case INT_MAX: //選項3,這個菜單項的值為0,通常可以避免這樣的情況,就不需要處理這個特殊的值了 break; case -1: //avi 錄像 break; case -2: //mkv錄像 break; case -3: //rdv錄像 break; case 10: //開始視頻 break; case 11: //停止視頻 break; default: { char * pfile = (char*)index; //選中了最後的文件菜單項,pfile為 “d:\\1.avi” 字元串的指針 } break; }
兩點註釋:
(1)上面的代碼裡面的菜單項的選中標記,都是在菜單字元串裡面手工指定的,這時 nDefaultMode 和 nDefaultValue 指定為0。
(2)上面代碼中的菜單項是在源代碼中硬編碼的,實際使用的時候可以動態生成,根據程式的狀態來組建菜單字元串,例如:
char szMenu[1024] = {0}; int n = 0; if (value == 2) n += sprintf(szMenu + n, "^"); n += sprintf(szMenu + n, "值2=2\n"); if (value == 4) n += sprintf(szMenu + n, "^"); n += sprintf(szMenu + n, "值4=4\n");
nDefaultMode=1時的示例
(1)模式1為相等模式 ( nDefaultMode = 1 ),當某個菜單項的數值等於輸入的 nDefaultValue 的時候,這個菜單項前面有選中標記
int val = 32; //nDefaultValue char szMenu[] = "整數1=1\n" "整數20=20\n" "整數32=32\n" "整數0x99=0x99\n" ; //註意上面的菜單字元串裡面沒有選中標記 //nDeaultMode = 1,當菜單項等於 nDefaultValue的時候顯示選中標記 val = auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 1, val); //返回值為當前選中的菜單項對應的值,如果沒有選擇菜單,這個值保持原來的不變
nDefaultMode=2時的示例
模式2為位模式 ( nDefaultMode = 2 ),當菜單項的數值所對應的位 與nDefaultValue位與的時候不為0,則菜單項前面顯示選中標記。
DWORD flags = 0x82; //當前的值 nDefaultValue char szMenu[] = "標記1=1\n" "標記2=2\n" "標記3=4\n" "標記4=8\n" "標記5=0x10\n" "標記6=0x20\n" "標記7=0x40\n" "標記8=0x80\n" ; //上面的菜單字元串內沒有選擇標記,程式自動根據 nDefaultValue 把對應的位加上選中標記 //nDefaultMode = 2 flags = (DWORD)auto_dynamenu::dynamenu(GetSafeHwnd(), 0, szMenu, 2, flags);
//返回值就是flags,如果沒有選擇菜單項,那麼這個值不變
待續
後續還要發表,《WIN 下的超級動態菜單(三)代碼》。
可以在下麵的鏈接下載代碼和示常式序:
http://files.cnblogs.com/files/tomview/dynamenu_20160524.rar