您的位置:首页 > 编程语言 > C语言/C++

学习win32 API开发6-给窗口添加菜单

2014-03-25 00:47 501 查看
看到别人做菜单有很多种,而我就比较不要麻烦就用较简单的来学习下吧,好用就行了。

一、用编辑资源来添加菜单

我用的VC++6.0,VS2013也是一样的!其他的工具嘛,没有用, 不知道。

先插入或者说添加一个类型为菜单(MENU)的资源文件,然后就保存下,保存到当前项目的目录下面,然后编辑这个资源文件,资源文件的后缀名是“.rc”,把菜单资源的ID改好。

现在添加菜单项吧,就做个简单的,比如,一个“文件”,然后下级添加个“退出”。同时把在属性里面填写好ID,比如:我的“退出”的ID是:IDM_EXIIT。

也可以直接打开resource.h头文件,直接在上面修改,前提是要生成这个文件,这个文件是在保存资源文件后生成的。

保存,下面要写响应菜单的过程函数了,在这之前先添加一个头文件#include "resource.h",完整程序:

#include "windows.h"
#include "resource.h"
void ShowErrMsg()
{
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
MessageBox(NULL, (LPTSTR)lpMsgBuf, "系统错误", MB_OK|MB_ICONSTOP);
//OutputDebugString();
LocalFree(lpMsgBuf);
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT umsg,WPARAM wparam,LPARAM lparam);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrecInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
TCHAR* clsName="myclass";
WNDCLASS mwc={sizeof(WNDCLASS)};

//设计窗口类
mwc.lpfnWndProc = WinProc;	//窗口处理函数
mwc.hbrBackground = (HBRUSH)COLOR_WINDOW;	//窗口背景色
mwc.lpszClassName = clsName;	// 窗口类名
mwc.style = CS_HREDRAW | CS_VREDRAW;	//窗口类型
mwc.cbClsExtra = 0;	//窗口扩展
mwc.cbWndExtra = 0;	//窗口实例扩展
mwc.hCursor = NULL;	//窗口鼠标光标
mwc.hIcon = NULL;	//窗口的最小化图标
mwc.lpszMenuName = (CHAR *)IDR_MENUmain;	//窗口菜单
mwc.hInstance = hInstance;	//实例句柄

//注册窗口类
RegisterClass(&mwc);

//创建窗口
HWND hwnd = CreateWindow(
clsName,	//类名,就是刚才注册的
//"HEHE",
TEXT("Windows的标题"),	//窗口标题
WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,	//外观样式
400,	//相对于父窗口的X坐标
150,	//相对于父窗口的Y坐标
400,	//窗口的宽
400,	//窗口的高
NULL,	//父窗口,没有就写NULL
LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENUmain)),	//窗口菜单,没有就可以写NULL
hInstance,	//当前应用程序的实例句柄
NULL);	//附加数据,没有,为NULL
if( hwnd == NULL)	//检查窗口是否创建成功
{
ShowErrMsg();
//DWORD err = GetLastError();
//TCHAR  er[123] ;
//wsprintf(er,"%i",err);
//MessageBox(NULL,er,TEXT("提示"),MB_ICONWARNING);

MessageBox(NULL,TEXT("创建窗口失败"),TEXT("提示"),MB_ICONWARNING);
return 0;
}
//显示窗口和更新窗口
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);

//消息循环
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//MessageBox(NULL,TEXT("你好 Windows 世界^_^"),TEXT("标题"),MB_OK);
return 0;
}
//消息处理过程函数
LRESULT CALLBACK WinProc(HWND hwnd,UINT umsg,WPARAM wparam,LPARAM lparam)
{
switch(umsg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd,&ps);
DrawText(ps.hdc,TEXT("你好啊"),6,&(ps.rcPaint),DT_CENTER);
EndPaint(hwnd,&ps);

}
return 0;
case WM_COMMAND:
{
switch(LOWORD(wparam))
{
case IDM_EXIIT:	PostQuitMessage(0);break;
case IDM_ABOUT: PostQuitMessage(0);break;
default:break;
}
}
return 0;
case WM_DESTROY:
{
PostQuitMessage(0);	//终止程序
return 0;
}
}
return DefWindowProc(hwnd,umsg,wparam,lparam);
}

要让菜单显示在窗口上面,第一种方法,那就是在设计窗口类的时候指定菜单:mwc.lpszMenuName = (CHAR *)IDR_MENUmain;,IDR_MENUmain是菜单的ID。

第二种方法是在创建窗口时候指定菜单:LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENUmain)),这两种方法都差不多的嘛!

这样菜单是可以显示了,但是还没有功能,点击菜单都不会有什么反应,那就要添加菜单的处理程序了,在过程函数WinProc里面实现。

当单击某个菜单项后,窗口处理程序(WinProc)会收到一条WM_COMMAND消息,收到WM_COMMAND后,可以用LOWORD取得窗口处理程序(WinProc)的第三个参数wparam的低数位,wParam的低位值表示菜单的资源ID,我们通过它的值与哪个菜单的ID相等,就知道用户点击了哪个菜单项。在窗口处理程序(WinProc)里面添加如下片段:

case WM_COMMAND:
{
switch(LOWORD(wparam))
{
case IDM_EXIIT:PostQuitMessage(0);break;
case IDM_ABOUT: PostQuitMessage(0);break;
default:break;
}
}

这里我的菜单是点击“退出”和“关于”都跟碘酒关闭按钮是一样的功能。



二、给菜单增加一点功能,能够在某一项菜单前面打上一个勾。

DWORD CheckMenuItem(HMENU hmenu,
UINT uIDCheckItem,
UINT uCheck);这个函数功能是复选或撤消复选指定的菜单条目,有3个参数,第一个是菜单句柄,第二个是要标记的那项菜单的ID,第三个是表示标记的状态。

BOOL CheckMenuRadioItem(HMEN hMENU,UINT idFirst,UINT idLast,UINT idCheck,UINT uFlags)这个函数是让菜单具有单选功能。

HMENU GetMenu(HWND hWnd)这个函数是获取指定窗口的菜单句柄。

HMENU GetSubMenu(HMENU hMenu,int nPos)这个函数是获取菜单的激活的子菜单的句柄。

在窗口处理程序(WinProc)的WM_COMMAND消息里面实现这个功能。
case WM_COMMAND:
{
HMENU hm=GetMenu(hwnd);//获取菜单句柄
HMENU hsm = GetSubMenu(hm,1);//获取菜单下级的菜单句柄
switch(LOWORD(wparam))
{
case IDM_EXIIT:PostQuitMessage(0);
break;
case IDM_ABOUT: 
CheckMenuItem(hsm,IDM_ABOUT,MF_CHECKED);//hsm用hm也可以
//CheckMenuRadioItem(hsm,0,1,0,MF_BYPOSITION);
break;
case IDM_HELP:
CheckMenuRadioItem(hsm,IDM_ABOUT,IDM_HELP,IDM_HELP,MF_BYCOMMAND);
break;
default:
break;
}
}
return 0;
这里可以对比下CheckMenuRadioItem(hsm,0,1,0,MF_BYPOSITION);和CheckMenuRadioItem(hsm,IDM_ABOUT,IDM_HELP,IDM_HELP,MF_BYCOMMAND);的不同处:第五个参数是指定idFirst,idLast,idCheck含义的值,如果此参数为MF_BYCOMMAND,则其他参数指定菜单项标识符,如果此参数为MF_BYPOSITION,则其他参数指定菜单项位置。这个不好理解啊!



三、菜单可以复选了(看到那个打勾了),但是还是不能去选选中,现在就实现下第一次点击选中(打勾),然后再次点击就取消选中(去掉对勾)。

就怎么简单怎么弄吧,我想到的是定义一个全局变量,就m吧!int m=0;
然后就在消息处理函数里面实现这个功能。

#include "windows.h"
#include "resource.h"

char m=0;
void ShowErrMsg()
{
//TCHAR szBuf[80];
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

MessageBox(NULL, (LPTSTR)lpMsgBuf, "系统错误", MB_OK|MB_ICONSTOP);
//OutputDebugString();
LocalFree(lpMsgBuf);
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT umsg,WPARAM wparam,LPARAM lparam);

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrecInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
TCHAR* clsName="myclass";
WNDCLASS mwc={sizeof(WNDCLASS)};

//设计窗口类
mwc.lpfnWndProc = WinProc;	//窗口处理函数
mwc.hbrBackground = (HBRUSH)COLOR_WINDOW;	//窗口背景色
mwc.lpszClassName = clsName;	// 窗口类名
mwc.style = CS_HREDRAW | CS_VREDRAW;	//窗口类型
mwc.cbClsExtra = 0;	//窗口扩展
mwc.cbWndExtra = 0;	//窗口实例扩展
mwc.lpszMenuName = MAKEINTRESOURCE(IDR_MENUmain);	//窗口菜单
//mwc.lpszMenuName = (CHAR *)IDR_MENUmain;
mwc.hInstance = hInstance;	//实例句柄

//注册窗口类
RegisterClass(&mwc);

//创建窗口
HWND hwnd = CreateWindow(
clsName,	//类名,就是刚才注册的
//"HEHE",
TEXT("Windows的标题"),	//窗口标题
WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,	//外观样式
400,	//相对于父窗口的X坐标
150,	//相对于父窗口的Y坐标
400,	//窗口的宽
400,	//窗口的高
NULL,	//父窗口,没有就写NULL
0,
//LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENUmain)),	//窗口菜单,也没有,写NULL
hInstance,	//当前应用程序的实例句柄
NULL);	//附加数据,没有,为NULL
if( hwnd == NULL)	//检查窗口是否创建成功
{
ShowErrMsg();
//DWORD err = GetLastError();
//TCHAR  er[123] ;
//wsprintf(er,"%i",err);
//MessageBox(NULL,er,TEXT("提示"),MB_ICONWARNING);

MessageBox(NULL,TEXT("创建窗口失败"),TEXT("提示"),MB_ICONWARNING);
return 0;
}
//显示窗口和更新窗口
ShowWindow(hwnd,SW_SHOW);
UpdateWindow(hwnd);

//消息循环
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//MessageBox(NULL,TEXT("你好 Windows 世界^_^"),TEXT("标题"),MB_OK);
return 0;
}

LRESULT CALLBACK WinProc(HWND hwnd,UINT umsg,WPARAM wparam,LPARAM lparam)
{
switch(umsg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd,&ps);
DrawText(ps.hdc,TEXT("你好啊"),6,&(ps.rcPaint),DT_CENTER);
EndPaint(hwnd,&ps);

}
return 0;
case WM_COMMAND:
{
HMENU hm=GetMenu(hwnd);			//获取菜单句柄
HMENU hsm = GetSubMenu(hm,1);	//获取菜单下级的菜单句柄

switch(LOWORD(wparam))
{
case IDM_EXIIT:	PostQuitMessage(0);
break;
case IDM_ABOUT:
if(m==0)
{
CheckMenuItem(hm,IDM_ABOUT,MF_CHECKED);	//选中
//CheckMenuRadioItem(hsm,0,1,0,MF_BYPOSITION);
m=1;	//选中标志,为1表示选中状态
}
else
{
CheckMenuItem(hsm,IDM_ABOUT,MF_UNCHECKED);	//取消选中
m=0;
}
break;
case IDM_HELP:
CheckMenuRadioItem(hsm,IDM_ABOUT,IDM_HELP,IDM_HELP,MF_BYCOMMAND);	//单选项
break;
default:
break;
}
}
return 0;
case WM_DESTROY:
{
PostQuitMessage(0);	//终止程序
return 0;
}
}
return DefWindowProc(hwnd,umsg,wparam,lparam);
}

至此,菜单就先学到这里了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c windows win32 vc++ winapi