windows程序设计(17):使用菜单

菜单应该算是比较简单的资源了,因为菜单的设计跟VB很像,图形界面的,你只要写菜单按钮的响应程序就行了。每个菜单都有自己的ID。菜单的消息是通过WM_COMMAND传给系统的,通过消息的wParam的低字节,就能获得ID号。需要注意的是,你最好把ID设成宏一样,见到名字就能看懂意思,不要用原配的那种数字。菜单的属性框中,还能选择菜单是否被选中,能否使用,是否变灰等等。

下来看看程序:

/*-----------------------------------------
   MENUDEMO.C -- Menu Demonstration
			  (c) Charles Petzold, 1998
  -----------------------------------------*/

#include <windows.h>
#include "resource.h"

#define ID_TIMER 1
#define MAX_COLOR 5

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

TCHAR szAppName[] = TEXT ("MenuDemo") ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR szCmdLine, int iCmdShow)
{
	
	HWND	hwnd ;
	MSG	 msg ;
	WNDCLASS wndclass ;
	
	wndclass.style	    = CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc   = WndProc ;
	wndclass.cbClsExtra    = 0 ;
	wndclass.cbWndExtra    = 0 ;
	wndclass.hInstance	= hInstance ;
	wndclass.hIcon	    = LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor	  = LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName  = szAppName ;
	wndclass.lpszClassName = szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"),
				  szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
					 WS_OVERLAPPEDWINDOW,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 NULL, 
					 //装载菜单
					 LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU2)),
					 hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

	HMENU	 hMenu ;
	HDC		 hdc;
	//定义一个数组,里面存储着背景菜单中的不同颜色消息
	static TCHAR idColor [MAX_COLOR] = { IDM_BKGND_WHITE,  IDM_BKGND_LTGRAY, IDM_BKGND_GRAY,
                                IDM_BKGND_DKGRAY, IDM_BKGND_BLACK } ;
    switch (message)
    {
	//菜单消息
    case WM_COMMAND:

		hMenu = GetMenu (hwnd) ;
		hdc = GetDC(hwnd);  
		//
		switch (LOWORD (wParam))
		{
			//暂时没有其他操作,只发出蜂鸣
			case IDM_FILE_NEW:
			case IDM_FILE_OPEN:
			case IDM_FILE_SAVE:
			case IDM_FILE_SAVE_AS:
			MessageBeep (0) ;
			return 0 ;
			
			//发出关闭窗口消息
			case IDM_APP_EXIT:
				SendMessage (hwnd, WM_CLOSE, 0, 0) ;
			return 0 ;
			
			//暂时没有其他操作
			case IDM_EDIT_CUT:
			case IDM_EDIT_COPY:
			case IDM_EDIT_PASTE:
			case IDM_EDIT_CLEAR:
				MessageBeep (0) ;
			return 0 ;
			
			//白色
			case IDM_BKGND_WHITE:			
				
				
				for(int i = 0;i < MAX_COLOR ; i++)
				{
					if(idColor[i] == IDM_BKGND_WHITE)
						CheckMenuItem (hMenu, idColor[i], MF_CHECKED) ;
					//
					else
					{
						CheckMenuItem (hMenu, idColor[i], MF_UNCHECKED) ;
					}
				}

				//改变wndclacc类里面的背景
				SetClassLong (hwnd, GCL_HBRBACKGROUND, 
					(LONG) GetStockObject (WHITE_BRUSH)) ;
				//刷新
				InvalidateRect (hwnd, NULL, TRUE) ;
				
				return 0;

			//浅灰
			case IDM_BKGND_LTGRAY:
				
				for(int i = 0;i < MAX_COLOR ; i++)
				{
					if(idColor[i] == IDM_BKGND_LTGRAY)
						CheckMenuItem (hMenu, idColor[i], MF_CHECKED) ;
					else
					{
						CheckMenuItem (hMenu, idColor[i], MF_UNCHECKED) ;
					}
				}

 
				SetClassLong (hwnd, GCL_HBRBACKGROUND, 
					(LONG) GetStockObject (LTGRAY_BRUSH)) ;
				InvalidateRect (hwnd, NULL, TRUE) ;
				return 0;

			//灰色
			case IDM_BKGND_GRAY:
				for(int i = 0;i < MAX_COLOR ; i++)
				{
					if(idColor[i] == IDM_BKGND_GRAY)
						CheckMenuItem (hMenu, idColor[i], MF_CHECKED) ;
					else
					{
						CheckMenuItem (hMenu, idColor[i], MF_UNCHECKED) ;
					}
				}				


				SetClassLong (hwnd, GCL_HBRBACKGROUND, 
					(LONG) GetStockObject (GRAY_BRUSH)) ;
				InvalidateRect (hwnd, NULL, TRUE) ;
				return 0;

			//深灰
			case IDM_BKGND_DKGRAY:
				for(int i = 0;i < MAX_COLOR ; i++)
				{
					if(idColor[i] == IDM_BKGND_DKGRAY)
						CheckMenuItem (hMenu, idColor[i], MF_CHECKED) ;
					else
					{
						CheckMenuItem (hMenu, idColor[i], MF_UNCHECKED) ;
					}
				}				


				SetClassLong (hwnd, GCL_HBRBACKGROUND, 
					(LONG) GetStockObject (DKGRAY_BRUSH)) ;
				InvalidateRect (hwnd, NULL, TRUE) ;
				return 0;


			case IDM_BKGND_BLACK:
				for(int i = 0;i < MAX_COLOR ; i++)
				{
					if(idColor[i] == IDM_BKGND_BLACK)
						CheckMenuItem (hMenu, idColor[i], MF_CHECKED) ;
					else
					{
						CheckMenuItem (hMenu, idColor[i], MF_UNCHECKED) ;
					}
				}					


				SetClassLong (hwnd, GCL_HBRBACKGROUND, 
					(LONG) GetStockObject (BLACK_BRUSH)) ;
				InvalidateRect (hwnd, NULL, TRUE) ;					    
				return 0 ;
			
			//打开计时器
			case IDM_TIMER_START:
				if (SetTimer (hwnd, ID_TIMER, 1000, NULL))
				{
					//不能再次打开
					EnableMenuItem (hMenu, IDM_TIMER_START, MF_GRAYED) ;
					//可以关闭计时器
					EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_ENABLED) ;
				}
				return 0 ;
			//关闭计时器
			case IDM_TIMER_STOP:
				//关闭计时器
				KillTimer (hwnd, ID_TIMER) ;
				//可以再次打开
				EnableMenuItem (hMenu, IDM_TIMER_START, MF_ENABLED) ;
				//不能关闭计时器
				EnableMenuItem (hMenu, IDM_TIMER_STOP,  MF_GRAYED) ;
				return 0 ;
			
			case IDM_APP_HELP:
				MessageBox (hwnd, TEXT ("自己百度"),
					  szAppName, MB_ICONEXCLAMATION | MB_OK) ;
				return 0 ;
			
			case IDM_APP_ABOUT:
				MessageBox (hwnd, TEXT ("Menu Demonstration Program\n")
                                 TEXT ("(c) Charles Petzold, 1998"),
					  szAppName, MB_ICONINFORMATION | MB_OK) ;
				return 0 ;
				ReleaseDC(hwnd,hdc);
		}
		break ;
		
	case WM_TIMER:
		MessageBeep (0) ;
		return 0 ;
			
	case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


 

在创建窗口时,就要加载菜单。程序中前两个菜单里的内容都没啥作用。只有文件->退出导致一个关闭窗口的消息WM_CLOSE。这个消息会导致WM_DESTROY。

有用的就是改变背景以及计时器,以及帮助。改变背景时,源程序玩了一个很投机取巧的花样,大家可以看Charles Petzold那本书,我在这里使用·了一个更为常见的作法,就是在每个消息下,写他自己的相应。但是,为了保证背景菜单里的内容始终保持单选效果,需要在每个消息下,把背景菜单中的别的选项置为没有选中,而把自己设为选中。而改变背景,也不像我一开始想象的使用画图的方法,而是直接改变wndclass中的背景,然后将客户区设为无效,重新刷新一遍。

计时器的内容比较简单,就是开始时发送计时器消息,结束时发送删除计时器的消息。唯一要注意的是,开始计时以后,计时器的开始就被设为灰色的了,不能再使用了,直到结束为止。同理也这样设计了计时器的结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值