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

看到别人做菜单有很多种,而我就比较不要麻烦就用较简单的来学习下吧,好用就行了。

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

我用的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;
}
}

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

学习win32 API开发6-给窗口添加菜单_第1张图片


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

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,则其他参数指定菜单项位置。这个不好理解啊!

学习win32 API开发6-给窗口添加菜单_第2张图片

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

就怎么简单怎么弄吧,我想到的是定义一个全局变量,就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);
}

至此,菜单就先学到这里了。


你可能感兴趣的:(windows开发)