《Windows程序设计》之鼠标3

感觉这次加的注释比较多,把全部代码拿上来了。

这个实现的效果与第一个比是一样的,但是实现方法不一样。

我认为值得学习的地方:

1、首次实现两个窗口类的注册,并且在子窗口类中加入cbWndExtra来保存子窗口状态。

2、循环创建25个子窗口,句柄保存到数组中。

3、首次一个函数中出现两个回调函数。

#include <windows.h>

#define DIVISIONS 5

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

TCHAR szChileClass[]=TEXT("Checker3_Child");

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow )
{
	static TCHAR szAppName[]=TEXT("Checker3");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	wndclass.style=CS_HREDRAW|CS_VREDRAW;
	wndclass.lpfnWndProc=WndProc;
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.hInstance=hInstance;
	wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.lpszClassName=szAppName;
	wndclass.lpszMenuName=NULL;

	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("Program requires Windows NT!"),szAppName,MB_ICONERROR);
		return 0;
	}

	//以下是注册子窗口类
	wndclass.lpfnWndProc=ChildWndProc;
	//cbWndExtra这个字段被设置成长整形变量的4个字节
	//这个字段通知Windows在内部结构中给基于这个窗口类的每个窗口预留4个字节的额外空间。
	//用户利用这些空间为每个窗口保存不同的信息。
	wndclass.cbWndExtra=sizeof(long);
	wndclass.hIcon=NULL;
	wndclass.lpszClassName=szChileClass;
	//注册子窗口类
	RegisterClass(&wndclass);


	hwnd=CreateWindow(szAppName,TEXT("Checker3 Mouse Hit-Test Demo"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
				CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,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)
{
	static HWND hwndChild[DIVISIONS][DIVISIONS];
	int cxBlock,cyBlock,x,y;
	switch(message)
	{
	//创建多个子窗口
	case WM_CREATE:
		for(x=0;x<DIVISIONS;x++)
			for(y=0;y<DIVISIONS;y++)
				//(HMENU)字段为每个子窗口ID,(HINSTANCE)创建子窗口时,必须调用GetWindowLong从Windows给窗口保留的结构中提取hInstnace的值.
				//hwndChild[x][y]保存窗口句柄
				hwndChild[x][y]=CreateWindow(szChileClass,NULL,WS_CHILDWINDOW|WS_VISIBLE,
													//y左移8位后与x进行位或运算 //获取应用实例的句柄
										0,0,0,0,hwnd,(HMENU)(y<<8|x),(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),NULL);
		return 0;
	//改变大小后,子窗口也要跟随移动改变
	case WM_SIZE:
		cxBlock=LOWORD(lParam)/DIVISIONS;
		cyBlock=HIWORD(lParam)/DIVISIONS;
		for(x=0;x<DIVISIONS;x++)
			for(y=0;y<DIVISIONS;y++)
				//改变窗口的位置和大小
				MoveWindow(hwndChild[x][y],x*cxBlock,y*cyBlock,cxBlock,cyBlock,TRUE);
		return 0;
	//这个在实际应用中其实不是有很大的影响。
	//只是在窗口下边与右边没有被子窗口覆盖的部分,会发出声音
	case WM_LBUTTONDOWN:
		MessageBeep(0);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}

//子窗口的回调函数
LRESULT CALLBACK ChildWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;
	switch(message)
	{
	case WM_CREATE:
		//设置前面为每个子窗口预留的cbWndExtra为0,为了保存矩形当前状态。
		SetWindowLong(hwnd,0,0);
		return 0;
	case WM_LBUTTONDOWN:
		//点击之后,取出cbWndExtra中的值与1做位异或运算
		SetWindowLong(hwnd,0,1^GetWindowLong(hwnd,0));
		//并使子窗口无效,重绘区域
		InvalidateRect(hwnd,NULL,FALSE);
		return 0;
	case WM_PAINT:
		hdc=BeginPaint(hwnd,&ps);
		//获取子窗口的区域
		GetClientRect(hwnd,&rect);
		//绘制方格
		Rectangle(hdc,0,0,rect.right,rect.bottom);
		//下面判断,是否绘制对角线
		if(GetWindowLong(hwnd,0))
		{
			MoveToEx(hdc,0,0,NULL);
			LineTo(hdc,rect.right,rect.bottom);
			MoveToEx(hdc,0,rect.bottom,NULL);
			LineTo(hdc,rect.right,0);
		}
		EndPaint(hwnd,&ps);
		return 0;
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}


你可能感兴趣的:(windows,null,application,callback,winapi)