()在Win32程式設計下建立菜單有兩種,一種是直接加載資源裡的菜單,另一種是動态建立
一.直接加載資源資源菜單,有兩種方法,要包含頭檔案resource.h
在"資源檔案"處右鍵"添加"中選擇"資源",在彈出的資源框中選擇"Menu",然後對菜單編輯,我這裡的菜單的ID都沒有改變
1. 在設計視窗類時将WNDCLASS結構體中的lpszMenuName成員關聯菜單ID,使用MAKEINTRESOURCE()這個宏,将資源
ID轉換為所對應的資源名,我的視窗類如下
//設計視窗類,該視窗類并不是C++中的類,隻是表示視窗特征的結構體
WNDCLASS MyWndClass; //WNDCLASS是個結構體,該結構體中的成員是指定視窗特征的資料
//WNDCLASS結構體
/*
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
Members
*/
//這兩個變量允許使用者請求Windows内部提供額外的空間以便額外資料與視窗
//執行個體發生聯系,通常不配置設定空間
MyWndClass.cbClsExtra = NULL;
MyWndClass.cbWndExtra = NULL;
//背景顔色,這裡有兩種方法
//GetStockObject()傳回的句柄是HGDIOBJ類型,需要轉換,
//可以加載畫刷,也可以加載畫筆,
//GetStockObject()參數的值有(看MSDN)
//BLACK_BRUSH 黑色畫刷
//DKGRAY_BRUSH 深灰色畫刷
//GRAY_BRUSH 灰色畫刷
//WHITE_BRUSH 白色畫刷
//MyWndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
MyWndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
//視窗的圖示,如果為NULL,系統将提供一個預設的圖示
//LoadIcon()加載圖示資源,傳回圖示句柄,
//如果加載系統标準的圖示第一個參數必須為NULL,第二個參數值為
//IDI_ERROR 錯誤圖示
//IDI_APPLICATION 預設應用程式圖示
//IDI_QUESTION 問号圖示
//IDI_EXCLAMATION 感歎号圖示
//IDI_ASTERISK 星号圖示
//IDI_WARNING 警告圖示
//IDI_WINLOGO Windows圖示
//IDI_HAND 與IDI_ERROR相同
//IDI_INFORMATION 消息圖示
//還有很多.....
MyWndClass.hIcon = LoadIcon(NULL,IDI_WINLOGO);
//光标,LoadCursor()的使用與LoadIcon()相同
MyWndClass.hCursor = LoadCursor(NULL,IDC_APPSTARTING);
MyWndClass.hInstance = hInstance; //目前執行個體的句柄
MyWndClass.lpfnWndProc = MyWindowProc; //視窗函數(消息處理函數),lpfnWndProc是個函數指針
MyWndClass.lpszClassName = szWindowClass; //視窗類名
//MyWndClass.lpszMenuName = NULL ;// 菜單,指定菜單資源的名字,NULL是表示沒有菜單,
MyWndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);//一種,MAKEINTRESOURCE()加載菜單
MyWndClass.style = CS_HREDRAW|CS_VREDRAW; //使用|把多種視窗樣式連接配接在一起
//視窗的樣式
//CS_HREDRAW 表示當水準方向寬度發生變化時重繪整個視窗
//CS_VREDRAW 表示當垂直方向高度發生變化時重繪整個視窗
//CS_NOCLOSE 禁用系統菜單中的Close指令,既是沒有關閉按鈕
//CS_DBLCLKS 當使用者輕按兩下滑鼠時向視窗過程函數發送滑鼠輕按兩下消息
而在建立視窗函數中菜單參數可以指定為NULL,如下:
//建立視窗,傳回視窗的句柄
HWND hWnd = CreateWindow(
szWindowClass, //視窗類名稱
szWindowTitle, //視窗标題
WS_OVERLAPPEDWINDOW, //視窗樣式,多種樣式
//這個樣式要與WNDCLASS的樣式差別開,這個是指定某個具體視窗的樣式
//而WNDCLASS的樣式是指基于該視窗類的所有視窗都具有的樣式
//WS_OVERLAPPED 一個可層疊視窗
//WS_CAPTION 有标題欄
//WS_SYSMENU 在标題欄帶有系統菜單,WS_CAPTION一起使用
//WS_THICKFRAME 具有可調邊框視窗
//WS_MINIMIZEBOX 有最小按鈕,必須設定WS_SYSMENU
//WS_MAXIMIZEBOX 有最大按鈕,必須設定WS_SYSMENU
CW_USEDEFAULT, //x坐标,預設
//CW_USEDEFAULT僅适用于WS_OVERLAPPED樣式視窗
CW_USEDEFAULT, //y坐标,預設
CW_USEDEFAULT, //寬
CW_USEDEFAULT, //高
NULL, //父視窗
NULL, //第一種加載菜單
//LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1)), //第二種加載菜單
//hMenu, //動态菜單
hInstance, //視窗執行個體标記
NULL //視窗建立時傳入的資料指針,
//多文檔時必須指向CLIENTCREATESTRUCT
);
2. 在設計視窗類時将WNDCLASS結構體中的lpszMenuName成員指定為NULL,直接在視窗的建立函數中加載
代碼如上面注釋的第二種加載菜單方法,使用LoadMenu()加載,第一個參數為視窗的執行個體,第二個參數為菜單資源,
一樣要使用MAKEINTRESOURCE()宏來将ID轉為資源名,
二. 動态菜單,不需要包含頭檔案resource.h,但需要定義一些宏,用于相應菜單的消息
//動态菜單
#define IDM_FILE_NEW 40001
#define IDM_FILE_OPEN 40002
#define IDM_EDIT_COPY 40003
#define IDM_EDIT_CUT 40004
我不清楚為什麼要從40001開始
建立菜單
//動态菜單
HMENU hMenu = CreateMenu(); //主菜單,水準
HMENU hMenuPop = CreateMenu(); //下拉的菜單,垂直
AppendMenu(hMenuPop,MF_STRING,IDM_FILE_NEW,_T("New"));
AppendMenu(hMenuPop,MF_STRING,IDM_FILE_OPEN,_T("Open"));
AppendMenu(hMenu,MF_POPUP,(unsigned int)hMenuPop,_T("File"));
//把下拉的菜單加載到主菜單第一個菜單,說的有點形象,
//自己運作程式看效果
hMenuPop = CreateMenu();
AppendMenu(hMenuPop,MF_STRING,IDM_EDIT_COPY,_T("Copy"));
AppendMenu(hMenuPop,MF_STRING,IDM_EDIT_CUT,_T("Cut"));
AppendMenu(hMenu,MF_POPUP,(unsigned int)hMenuPop,_T("Edit"));
加載菜單,直接在建立視窗函數中把動态菜單的主菜單句柄hMenu給函數中的菜單參數,代碼如上已經注釋的代碼
下面代碼執行的結果是加載動态菜單的結果,直接加載資源裡的菜單已經注釋起來了,代碼中有對菜單消息的相應,
看消息處理函數,代碼是基于Windows程式設計|SDK我的這篇文章裡的代碼修改的
//開發工具:VS2008
//使用 Unicode 字元集
#include <Windows.h>
#include <tchar.h> //_T或_TEXT需要的頭檔案
//#include "resource.h"
//設計一個視窗類;
//注冊視窗類;
//建立視窗;
//顯示及更新視窗。
//消息循環
//視窗函數
//動态菜單
#define IDM_FILE_NEW 40001
#define IDM_FILE_OPEN 40002
#define IDM_EDIT_COPY 40003
#define IDM_EDIT_CUT 40004
//全局變量
TCHAR szWindowClass[] = _T("示範程式");
TCHAR szWindowTitle[] = _T("主視窗标題");
//定義的視窗過程函數,是個回調函數,意思是該函數不是在程式中直接調用
//而是在特定的事件或條件發生時由Windows系統調用,對事件或條件的響應
LRESULT CALLBACK MyWindowProc(
HWND hwnd, // handle to window 視窗句柄
UINT uMsg, // message identifier 消息辨別
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
//程式的入口函數
int WINAPI WinMain(
HINSTANCE hInstance, //記錄程式目前運作的執行個體的句柄
HINSTANCE hPrevInstance, //已經失去了意義,總為NULL
LPSTR lpCmdLine, //指令行參數,記錄目前運作程式的路徑
int nShowCmd //指定程式視窗應該如何顯示,通常不檢查這個參數的值
)
{
//設計視窗類,該視窗類并不是C++中的類,隻是表示視窗特征的結構體
WNDCLASS MyWndClass; //WNDCLASS是個結構體,該結構體中的成員是指定視窗特征的資料
//WNDCLASS結構體
/*
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
Members
*/
//這兩個變量允許使用者請求Windows内部提供額外的空間以便額外資料與視窗
//執行個體發生聯系,通常不配置設定空間
MyWndClass.cbClsExtra = NULL;
MyWndClass.cbWndExtra = NULL;
//背景顔色,這裡有兩種方法
//GetStockObject()傳回的句柄是HGDIOBJ類型,需要轉換,
//可以加載畫刷,也可以加載畫筆,
//GetStockObject()參數的值有(看MSDN)
//BLACK_BRUSH 黑色畫刷
//DKGRAY_BRUSH 深灰色畫刷
//GRAY_BRUSH 灰色畫刷
//WHITE_BRUSH 白色畫刷
//MyWndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
MyWndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
//視窗的圖示,如果為NULL,系統将提供一個預設的圖示
//LoadIcon()加載圖示資源,傳回圖示句柄,
//如果加載系統标準的圖示第一個參數必須為NULL,第二個參數值為
//IDI_ERROR 錯誤圖示
//IDI_APPLICATION 預設應用程式圖示
//IDI_QUESTION 問号圖示
//IDI_EXCLAMATION 感歎号圖示
//IDI_ASTERISK 星号圖示
//IDI_WARNING 警告圖示
//IDI_WINLOGO Windows圖示
//IDI_HAND 與IDI_ERROR相同
//IDI_INFORMATION 消息圖示
//還有很多.....
MyWndClass.hIcon = LoadIcon(NULL,IDI_WINLOGO);
//光标,LoadCursor()的使用與LoadIcon()相同
MyWndClass.hCursor = LoadCursor(NULL,IDC_APPSTARTING);
MyWndClass.hInstance = hInstance; //目前執行個體的句柄
MyWndClass.lpfnWndProc = MyWindowProc; //視窗函數(消息處理函數),lpfnWndProc是個函數指針
MyWndClass.lpszClassName = szWindowClass; //視窗類名
MyWndClass.lpszMenuName = NULL ;// 菜單,指定菜單資源的名字,NULL是表示沒有菜單,
//MyWndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);//一種,MAKEINTRESOURCE()加載菜單
MyWndClass.style = CS_HREDRAW|CS_VREDRAW; //使用|把多種視窗樣式連接配接在一起
//視窗的樣式
//CS_HREDRAW 表示當水準方向寬度發生變化時重繪整個視窗
//CS_VREDRAW 表示當垂直方向高度發生變化時重繪整個視窗
//CS_NOCLOSE 禁用系統菜單中的Close指令,既是沒有關閉按鈕
//CS_DBLCLKS 當使用者輕按兩下滑鼠時向視窗過程函數發送滑鼠輕按兩下消息
//注冊視窗類,告訴Windows系統視窗類設計好了
RegisterClass(&MyWndClass);
//動态菜單
HMENU hMenu = CreateMenu(); //主菜單,水準
HMENU hMenuPop = CreateMenu(); //下拉的菜單,垂直
AppendMenu(hMenuPop,MF_STRING,IDM_FILE_NEW,_T("New"));
AppendMenu(hMenuPop,MF_STRING,IDM_FILE_OPEN,_T("Open"));
AppendMenu(hMenu,MF_POPUP,(unsigned int)hMenuPop,_T("File"));
//把下拉的菜單加載到主菜單第一個菜單,說的有點形象,
//自己運作程式看效果
hMenuPop = CreateMenu();
AppendMenu(hMenuPop,MF_STRING,IDM_EDIT_COPY,_T("Copy"));
AppendMenu(hMenuPop,MF_STRING,IDM_EDIT_CUT,_T("Cut"));
AppendMenu(hMenu,MF_POPUP,(unsigned int)hMenuPop,_T("Edit"));
//建立視窗,傳回視窗的句柄
HWND hWnd = CreateWindow(
szWindowClass, //視窗類名稱
szWindowTitle, //視窗标題
WS_OVERLAPPEDWINDOW, //視窗樣式,多種樣式
//這個樣式要與WNDCLASS的樣式差別開,這個是指定某個具體視窗的樣式
//而WNDCLASS的樣式是指基于該視窗類的所有視窗都具有的樣式
//WS_OVERLAPPED 一個可層疊視窗
//WS_CAPTION 有标題欄
//WS_SYSMENU 在标題欄帶有系統菜單,WS_CAPTION一起使用
//WS_THICKFRAME 具有可調邊框視窗
//WS_MINIMIZEBOX 有最小按鈕,必須設定WS_SYSMENU
//WS_MAXIMIZEBOX 有最大按鈕,必須設定WS_SYSMENU
CW_USEDEFAULT, //x坐标,預設
//CW_USEDEFAULT僅适用于WS_OVERLAPPED樣式視窗
CW_USEDEFAULT, //y坐标,預設
CW_USEDEFAULT, //寬
CW_USEDEFAULT, //高
NULL, //父視窗
NULL, //第一種加載菜單
//LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1)), //第二種加載菜單
//hMenu, //動态菜單
hInstance, //視窗執行個體标記
NULL //視窗建立時傳入的資料指針,
//多文檔時必須指向CLIENTCREATESTRUCT
);
//如果視窗建立失敗
if(!hWnd)
return 0;
//顯示并更新視窗
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
//消息循環,WM_QIUT才停止循環,或程式已經推出
/*
BOOL GetMessage(
LPMSG lpMsg, //指向一個消息結構體MSG結構體對象,
//用于儲存從消息隊列中擷取的消息
HWND hWnd, //指向某個視窗的句柄,NULL是指擷取程式的所有消息
UINT wMsgFilterMin, //消息隊列中消息ID的最小值
UINT wMsgFilterMax //消息隊列中消息ID的最大值
//最後兩個參數适用于指定消息ID的範圍,如果都為0,表示擷取消息隊列所有消息
);
//函數傳回值總為TRUE,當獲得WM_QIUT傳回0,出錯時傳回-1
//菜單中的"檔案"中的"退出",視窗的"X"關閉按鈕,視窗上系統菜單的"關閉"指令
//上面的3中情況都會發送一個WM_QUIT消息
*/
MSG Msg;
while(GetMessage(&Msg,NULL,0,0))
{
TranslateMessage(&Msg); //讓Windows為與鍵盤相關的消息做一些轉換
DispatchMessage(&Msg); //分派消息到視窗過程函數中對消息處理
}
return 1;
}
//視窗過程函數的實作(消息處理函數)
LRESULT CALLBACK MyWindowProc(
HWND hwnd, // handle to window 視窗句柄
UINT uMsg, // message identifier 消息辨別
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_PAINT:
{
TCHAR str[] = _T("這是一個Windows的SDK程式!");
HDC hDc;
PAINTSTRUCT Ps;
hDc = BeginPaint(hwnd,&Ps); //擷取裝置環境句柄
SetTextColor(hDc,RGB(13,25,200)); //設定文本顔色
TextOut(hDc,0,0,str,18); //輸出文字
EndPaint(hwnd,&Ps); //釋放資源
break;
}
case WM_CLOSE: //點選"X"按鈕時發送此消息,使消息循環停止
if(IDYES == MessageBox(hwnd,_T("是否要退出?"),_T("提示"),MB_YESNO))
{
DestroyWindow(hwnd); //銷毀視窗,發送WM_DESTROY消息,注意程式程序還沒退出
}
break;
case WM_DESTROY:
PostQuitMessage(NULL); //程序結束,完全退出程式
break;
case WM_LBUTTONDOWN:
MessageBox(hwnd,_T("滑鼠左鍵按下"),_T("提示"),MB_OK);
break;
case WM_COMMAND: //相應菜單消息
switch(LOWORD(wParam))
{
//相應直接加載的菜單消息
/*
case ID_40001: MessageBox(hwnd,_T("菜單檔案裡的建立"),_T("菜單"),MB_OK); break;
case ID_40002: MessageBox(hwnd,_T("菜單檔案裡的打開"),_T("菜單"),MB_OK);break;
case ID_40003: MessageBox(hwnd,_T("菜單檔案裡的儲存"),_T("菜單"),MB_OK);break;
case ID_40004: MessageBox(hwnd,_T("菜單檔案裡的另存為"),_T("菜單"),MB_OK);break;
case ID_40005: PostQuitMessage(0); break;
*/
//相應動态菜單消息
case IDM_FILE_NEW: MessageBox(hwnd,_T("動态菜單File裡的New"),_T("菜單"),MB_OK); break;
case IDM_FILE_OPEN: MessageBox(hwnd,_T("動态菜單File裡的Open"),_T("菜單"),MB_OK); break;
case IDM_EDIT_COPY: MessageBox(hwnd,_T("動态菜單Edit裡的Copy"),_T("菜單"),MB_OK); break;
case IDM_EDIT_CUT: MessageBox(hwnd,_T("動态菜單Edit裡的Cut"),_T("菜單"),MB_OK); break;
}
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam); //處理未處理的消息
break;
}
return 0;
}