Windows程序设计 第7章

Windows程序设计 第7章 移动鼠标画点 按下鼠标画线

#include <Windows.h>
#define MAXPOINTS 1000;

LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数  WndProc函数的返回值类型为LRESULT。该类型等价于LONG.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndPorc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	return msg.wParam;
}

LRESULT CALLBACK WndPorc(HWND  hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	HDC          hdc;
	PAINTSTRUCT  ps;
	//RECT         rect;
	static POINT  pt[1000];
	static int iCount;
	int i, j;


	switch (message)
	{
	case  WM_LBUTTONDOWN: // 当要获取系统的字体时
		iCount = 0;
		InvalidateRect(hwnd,NULL,TRUE);
		return 0;
	case WM_MOUSEMOVE:
		if (lparam & MK_LBUTTON && iCount < 1000) 
		{
			pt[iCount].x = LOWORD(lparam);
			pt[iCount++].y = HIWORD(lparam);

			hdc = GetDC(hwnd);
			SetPixel(hdc, LOWORD(lparam), HIWORD(lparam), RGB(0, 0, 0));
			ReleaseDC(hwnd, hdc);
		
		}
		return 0;
	case WM_LBUTTONUP:
		InvalidateRect(hwnd, NULL, FALSE);
		return 0;
	case WM_PAINT:   //绘制窗口
		hdc = BeginPaint(hwnd, &ps);  

		SetCursor(LoadCursor(NULL, IDC_WAIT));
			ShowCursor(TRUE);
		for (int i = 0; i < iCount - 1; i++)
			for (int j = i + 1; j < iCount; j++)
			{
				MoveToEx(hdc, pt[i].x, pt[i].y, NULL);
				LineTo(hdc, pt[j].x, pt[j].y);
			}
			ShowCursor(FALSE);
			SetCursor(LoadCursor(NULL, IDC_ARROW));


		EndPaint(hwnd, &ps);
		return 0;

		
	case WM_DESTROY:  //处理窗口关闭的消息
		PostQuitMessage(0);
		return 0;

	}
	return DefWindowProc(hwnd, message, wparam, lparam);

}

运行效果
在这里插入图片描述

点击客户区里面的小方框 画一个X 再次点击取消X

#include <Windows.h>
#define DIVISIONS 5

LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数  WndProc函数的返回值类型为LRESULT。该类型等价于LONG.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndPorc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	return msg.wParam;
}

LRESULT CALLBACK WndPorc(HWND  hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	static bool fstate[DIVISIONS][DIVISIONS];
	static int cxblock, cyblock;
	HDC hdc;
	int x, y;
	PAINTSTRUCT ps;
	RECT rect;

	switch (message)
	{
	case WM_SIZE:

		//每一个小矩形的大小
		cxblock = LOWORD(lparam) / DIVISIONS;
		cyblock = HIWORD(lparam) / DIVISIONS;
		return 0;


	case WM_LBUTTONDOWN:

		//获取鼠标位置
		x = LOWORD(lparam) / cxblock;
		y = HIWORD(lparam) / cyblock;

		//判断鼠标时候在客户区

		if (x < DIVISIONS && y < DIVISIONS)
		{
			fstate[x][y] ^= 1; //异或操作,相同为0,不同为1

							   //确实是哪个小矩形按下

			rect.left = x * cxblock;
			rect.top = y * cyblock;
			rect.right = (x + 1) * cxblock;
			rect.bottom = (y + 1) * cyblock;
			InvalidateRect(hwnd, &rect, false);
		}
		else
			MessageBeep(0);

		return 0;


	case WM_PAINT:

		//显示每个矩形的位置
		hdc = BeginPaint(hwnd, &ps);
		for (x = 0; x < DIVISIONS; x++)
			for (y = 0; y < DIVISIONS; y++)
			{
				Rectangle(hdc, x * cxblock, y * cyblock, (x + 1) * cxblock, (y + 1) * cyblock);//画矩形

				//为true,则在一个小矩形中画对角线

				if (fstate[x][y])
				{
					MoveToEx(hdc, x * cxblock, y * cyblock, NULL);
					LineTo(hdc, (x + 1) * cxblock, (y + 1)* cyblock);

					MoveToEx(hdc, x * cxblock, (y + 1) * cyblock, NULL);
					LineTo(hdc, (x + 1) * cxblock, y * cyblock);
				}

			}
		EndPaint(hwnd, &ps);
		return 0;


	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	
	}
	return DefWindowProc(hwnd, message, wparam, lparam);

}

显示效果
在这里插入图片描述

点击客户区里面的小方框 画一个X 再次点击取消X 增加键盘接口

#include <Windows.h>
#define DIVISIONS 5

LRESULT CALLBACK WndPorc(HWND, UINT, WPARAM, LPARAM);//设置回调函数  WndProc函数的返回值类型为LRESULT。该类型等价于LONG.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndPorc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	return msg.wParam;
}

LRESULT CALLBACK WndPorc(HWND  hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	static bool fstate[DIVISIONS][DIVISIONS];
	static int cxblock, cyblock;
	HDC hdc;
	int x, y;
	PAINTSTRUCT ps;
	RECT rect;
	POINT point;

	switch (message)
	{
	case WM_SIZE:

		//每一个小矩形的大小
		cxblock = LOWORD(lparam) / DIVISIONS;
		cyblock = HIWORD(lparam) / DIVISIONS;
		return 0;

	case WM_SETFOCUS:
		ShowCursor(TRUE);//显示光标
		return 0;
	case WM_KILLFOCUS:
		ShowCursor(FALSE);//隐藏光标
		return 0;
	case  WM_KEYDOWN:
		GetCursorPos(&point);//判断指针位置
		ScreenToClient(hwnd,&point);//屏幕坐标转换为客户坐标
		x = max(0,min(DIVISIONS-1,point.x/cxblock));//获得x点
		y = max(0, min(DIVISIONS - 1, point.y / cyblock));//获得y点
		switch (wparam)
		{
		case VK_UP:
			y--;
			break;
		case   VK_DOWN:
			y++;
			break;
		case   VK_LEFT:
			x--;
			break;
		case   VK_RIGHT:
			x++;
			break;
		case   VK_HOME:
			x = y = 0;
			break;
		case   VK_END:
			x = y = DIVISIONS - 1;
			break;
		case   VK_RETURN:
		case   VK_SPACE:
			SendMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON,
				MAKELONG(x * cxblock, y * cyblock));
			break;

		}
		x = (x + DIVISIONS) % DIVISIONS;
		y = (y + DIVISIONS) % DIVISIONS;
		point.x = x * cxblock + cxblock / 2;
		point.y = y * cyblock + cyblock / 2;

		ClientToScreen(hwnd, &point);
		SetCursorPos(point.x, point.y);

	

		return 0;
	case WM_LBUTTONDOWN:

		//获取鼠标位置
		x = LOWORD(lparam) / cxblock;
		y = HIWORD(lparam) / cyblock;

		//判断鼠标时候在客户区

		if (x < DIVISIONS && y < DIVISIONS)
		{
			fstate[x][y] ^= 1; //异或操作,相同为0,不同为1

							   //确实是哪个小矩形按下

			rect.left = x * cxblock;
			rect.top = y * cyblock;
			rect.right = (x + 1) * cxblock;
			rect.bottom = (y + 1) * cyblock;
			InvalidateRect(hwnd, &rect, false);
		}
		else
			MessageBeep(0);

		return 0;


	case WM_PAINT:

		//显示每个矩形的位置
		hdc = BeginPaint(hwnd, &ps);
		for (x = 0; x < DIVISIONS; x++)
			for (y = 0; y < DIVISIONS; y++)
			{
				Rectangle(hdc, x * cxblock, y * cyblock, (x + 1) * cxblock, (y + 1) * cyblock);//画矩形

				//为true,则在一个小矩形中画对角线

				if (fstate[x][y])
				{
					MoveToEx(hdc, x * cxblock, y * cyblock, NULL);
					LineTo(hdc, (x + 1) * cxblock, (y + 1)* cyblock);

					MoveToEx(hdc, x * cxblock, (y + 1) * cyblock, NULL);
					LineTo(hdc, (x + 1) * cxblock, y * cyblock);
				}

			}
		EndPaint(hwnd, &ps);
		return 0;


	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	
	}
	return DefWindowProc(hwnd, message, wparam, lparam);

}

显示结果
在这里插入图片描述

CHECKER3.cpp 代码

#include <windows.h>

#define DIVISIONS 5

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

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


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndProc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	wndclass.lpfnWndProc = ChildWndProc;
	wndclass.cbWndExtra = sizeof(long);
	wndclass.hIcon = NULL;
	wndclass.lpszClassName = szChildClass;

	RegisterClass(&wndclass);

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	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++)                      //创建25个子窗口(5行5列)
			for (y = 0; y < DIVISIONS; y++)
				hwndChild[x][y] = CreateWindow(szChildClass, NULL,
					WS_CHILDWINDOW | WS_VISIBLE,
					0, 0, 0, 0,      //注意对0,0,0,0的理解,应该初始化的时候,在WM_CREASTE中还不知道主窗口的大小,也就更不知道子窗口的大小,
									 //只是临时指定,在wm_size消息中,通过movewindow就真正确定了窗口的大小

					hwnd, (HMENU)(y << 8 | x),           //子窗口标识符,确定唯一的窗口
					(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), //获取应用程序实例句柄,可以使用全局的hInstance
					NULL);

		//对于这个嵌套循环,每创建一个子窗口,都会想子窗口产生一个WM_CREATE消息,也就是说,在这个嵌套循环中一共要调用25次ChildWndProc子窗口过程
		//对每个子窗口产生的WM_CREATE消息进行处理
		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);
		//特别要注意movewindow这个语句,如果不清楚,你就无法知道程序的执行流程,只能默默糊糊了解大概;
		//movewindow重新指定每个子窗口在主窗口客户区的位置和每个子窗口的大小
		//当重新移动每一个子窗口时,子窗口无效,若最后一个参数为true,则会产生WM_PAINT消息,(这wm_paint消息是传个子窗口过程的),
		//这本例中参数为true,也就是说,对于每一个子窗口无效时,都会调用ChildWndProc子窗口过程,对WM_PAINT消息进行处理,绘出每个子窗口图形
		//
		//当重新移动每一个子窗口时,子窗口无效,若最后一个参数为false,则不会产生WM_PAINT消息,读者可以把参数改为false,就会发现,窗口了上什么都没有

		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:
		SetWindowLong(hwnd, 0, 0);       //用零填充额外的空间
		return 0;

	case WM_LBUTTONDOWN:
		SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));//对额外的空间里的值取反,判断是否单击了子窗口(异或操作,相同为0,不同为1)
		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);
}

CHECKER4.cpp 代码

#include <windows.h>

#define DIVISIONS 5

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

int   idFocus = 0;
TCHAR szChildClass[] = TEXT("Checker4_Child");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndProc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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


	wndclass.lpfnWndProc = ChildWndProc;
	wndclass.cbWndExtra = sizeof(long);
	wndclass.hIcon = NULL;
	wndclass.lpszClassName = szChildClass;

	RegisterClass(&wndclass);

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	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++)
				hwndChild[x][y] = CreateWindow(szChildClass, NULL,
					WS_CHILDWINDOW | WS_VISIBLE,//即便设置了WS_TAPSTOP,子窗口也无法自动获得输入焦点
					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_SETFOCUS:
		SetFocus(GetDlgItem(hwnd, idFocus));  //使得子窗口获得输入焦点,如果没有设置这条语句,子窗口是无法获得输入焦点的(也就是说开始运行程序的时候,你在桌面上按下键盘,是没有任何反应的),意思就是输入焦点还在主窗口上。想要使得运行时,子窗口获得输入焦点,必须要有这条语句


											  //可以把程序中所出现的setfocus语句注释起来,将会发现你在桌面上按下键盘,是没有任何反应的,同时点击子窗口,子窗口也不会获得输入焦点,说明在子窗口上单击,子窗口是不会自动获得焦点的,要想子窗口获得输入焦点,必须设置setfocus语句

		return 0;

		// 按键按下消息时,可能会更改焦点窗口

	case WM_KEYDOWN:
		x = idFocus & 0xFF;
		y = idFocus >> 8;

		switch (wParam)
		{
		case VK_UP:    y--;                    break;
		case VK_DOWN:  y++;                    break;
		case VK_LEFT:  x--;                    break;
		case VK_RIGHT: x++;                    break;
		case VK_HOME:  x = y = 0;              break;
		case VK_END:   x = y = DIVISIONS - 1;  break;
		default:       return 0;
		}

		x = (x + DIVISIONS) % DIVISIONS;
		y = (y + DIVISIONS) % DIVISIONS;

		idFocus = y << 8 | x;

		SetFocus(GetDlgItem(hwnd, idFocus)); //让子窗口ID为idFocus的窗口具有输入焦点
		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:
		SetWindowLong(hwnd, 0, 0);       // 开/关标志
		return 0;

	case WM_KEYDOWN:
		// 将大多数按键发送到父窗口

		if (wParam != VK_RETURN && wParam != VK_SPACE)  //若不是这两个虚拟键,则交给父窗口处理,是这两个键,则执行WM_LBUTTONDOWN

														//实际上处理回车和空格消息外,其它的必须交给父窗口处理,因为只有父窗口才能设置子窗口具有输入焦点

														//父窗口可以通过GetdlgItem获得子窗口句柄,而在子窗口设置就没有办法获取其它兄弟窗口的句柄
		{
			SendMessage(GetParent(hwnd), message, wParam, lParam);
			return 0;
		}
		// 对于返回和空间,请通过切换正方形

	case WM_LBUTTONDOWN:
		SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));
		SetFocus(hwnd); //使得鼠标按下的那个子窗口获得焦点
		InvalidateRect(hwnd, NULL, FALSE);
		return 0;

		//对于焦点消息,请使重新打印窗口无效

	case WM_SETFOCUS:
		idFocus = GetWindowLong(hwnd, GWL_ID); //获取有输入焦点的子窗口ID

											   // 落空

	case WM_KILLFOCUS:
		InvalidateRect(hwnd, NULL, TRUE);
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		GetClientRect(hwnd, &rect);
		Rectangle(hdc, 0, 0, rect.right, rect.bottom);

		//画“x”标记

		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);
		}

		// 绘制“焦点”矩形

		if (hwnd == GetFocus())
		{
			rect.left += rect.right / 10;
			rect.right -= rect.left;
			rect.top += rect.bottom / 10;
			rect.bottom -= rect.top;

			SelectObject(hdc, GetStockObject(NULL_BRUSH));
			SelectObject(hdc, CreatePen(PS_DASH, 0, 0));
			Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
			DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN)));
		}

		EndPaint(hwnd, &ps);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

BLOCKOUT2.cpp 鼠标画矩形

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//设置回调函数  WndProc函数的返回值类型为LRESULT。该类型等价于LONG.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndProc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}


	return msg.wParam;
}

void DrawBoxOutLine(HWND hwnd,POINT ptBeg,POINT ptEnd) 
{
	HDC hdc;
	hdc = GetDC(hwnd);

	SetROP2(hdc,R2_NOT);
	SelectObject(hdc,GetStockObject(NULL_BRUSH));
	Rectangle(hdc,ptBeg.x,ptBeg.y,ptEnd.x,ptEnd.y);

	ReleaseDC(hwnd,hdc);


}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static BOOL fBlocking, fValidBox;
	static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd;
	HDC hdc;
	PAINTSTRUCT ps;

	switch (message)
	{
	case WM_LBUTTONDOWN:
		ptBeg.x = ptEnd.x = LOWORD(lParam);
		ptBeg.y = ptEnd.y = HIWORD(lParam);

		DrawBoxOutLine(hwnd, ptBeg, ptEnd);

		SetCapture(hwnd);
		SetCursor(LoadCursor(NULL, IDC_CROSS));

		fBlocking = TRUE;
		return 0;

	case WM_MOUSEMOVE:
		if (fBlocking)
		{
			SetCursor(LoadCursor(NULL, IDC_CROSS));

			DrawBoxOutLine(hwnd, ptBeg, ptEnd);

			ptEnd.x = LOWORD(lParam);
			ptEnd.y = HIWORD(lParam);

			DrawBoxOutLine(hwnd, ptBeg, ptEnd);
		}
		return 0;

	case WM_LBUTTONUP:
		if (fBlocking)
		{
			DrawBoxOutLine(hwnd, ptBeg, ptEnd);

			ptBoxBeg = ptBeg;
			ptBoxEnd.x = LOWORD(lParam);
			ptBoxEnd.y = HIWORD(lParam);

			ReleaseCapture();
			SetCursor(LoadCursor(NULL, IDC_ARROW));

			fBlocking = FALSE;
			fValidBox = TRUE;

			InvalidateRect(hwnd, NULL, TRUE);
		}
		return 0;

	case WM_CHAR:
		if (fBlocking & (wParam == '\x1B')) // i.e., Escape
		{
			DrawBoxOutLine(hwnd, ptBeg, ptEnd);

			ReleaseCapture();
			SetCursor(LoadCursor(NULL, IDC_ARROW));

			fBlocking = FALSE;
		}
		return 0;

	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);

		if (fValidBox)
		{
			SelectObject(hdc, GetStockObject(BLACK_BRUSH));
			Rectangle(hdc, ptBoxBeg.x, ptBoxBeg.y,
				ptBoxEnd.x, ptBoxEnd.y);
		}

		if (fBlocking)
		{
			SetROP2(hdc, R2_NOT);
			SelectObject(hdc, GetStockObject(NULL_BRUSH));
			Rectangle(hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y);
		}

		EndPaint(hwnd, &ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}

SYSMETS4.cpp 显示文本框 新加鼠标滚轮功能

#include <windows.h>

#include "sysmets.h"


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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, PSTR szCmdLine, int iCmdShow)
{
	static WCHAR szAppName[] = TEXT("HelloWindows");  //定义app名称

	HWND     hwnd;
	MSG      msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;						//指定窗口类型,各种“类风格”(详见下方↓)可以使用按位或操作符组合起来
	wndclass.lpfnWndProc = WndProc;									//指定窗口过程(必须是回调函数) *
																	//下面两个字段用于在类结构和 Windows内部维护的窗口结构中预留
																	//一些额外的空间:
	wndclass.cbClsExtra = 0;										//预留的额外空间,一般为 0
	wndclass.cbWndExtra = 0;										//预留的额外空间,一般为 0
																	//接下来的字段表示应用程序的实例句柄(是WinMain的一个参数):
	wndclass.hInstance = hInstance;									//应用程序的实例句柄
																	//下面的语句为所有基于该窗口类的窗口设定一个图标:
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);				//为所有基于该窗口类的窗口设定一个图标
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);					//为所有基于该窗口类的窗口设定一个鼠标指针
																	/*
																	下一个字段为这类窗口的客户区指定了背景色。
																	字段名hbrBackground 的前缀hbr表示“画刷的句柄”(handle to a brush)。
																	画刷是一个图形学术语,表示用于区域填充的像素着色模式。
																	Windows有几个标准的画刷,又称“库存”画刷。
																	下面对GetStockObject的调用返回一个白色画刷的句柄:
																	*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//指定窗口背景色
																	//接下来的一个字段指定了窗口类的菜单。
																	//由于程序 HELLOWIN不带任何菜单,所以该字段被设为NULL:
	wndclass.lpszMenuName = NULL;									//指定窗口菜单
																	//最后,必须为窗口类赋予一个名称。对一个小程序来说,
																	//这个名称可以简单地用程序名表示,
																	//如保存在变量szAppName中的字符串“HelloWin”:
	wndclass.lpszClassName = szAppName;								//指定窗口类名  *

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

	hwnd = CreateWindow(szAppName,                        //窗口类名
		TEXT("THIS  IS  YANXU  WINDOWS"), //窗口标题
		WS_OVERLAPPEDWINDOW,              //窗口样式
		CW_USEDEFAULT,	                  //初始x位置
		CW_USEDEFAULT,                    //初始y位置
		CW_USEDEFAULT,                    //初始x尺寸
		CW_USEDEFAULT,                    //初始y尺寸
		NULL,                             //父窗口句柄
		NULL,							  //窗口菜单句柄
		hInstance,						  //程序实例句柄
		NULL                              //创建参数
	);


	ShowWindow(hwnd, iCmdShow);  //显示窗口 函  数用于设置窗口的显示状态。
	UpdateWindow(hwnd);  //函数绕过应用程序的消息队列,直接发送 WM_PAINT 消息给指定窗口的窗口过程


	while (GetMessage(&msg, NULL, 0, 0))   //函数的作用是从当前线程的消息队列里获取一个消息并填入 MSG 结构 中。
	{
		TranslateMessage(&msg);  //函数将虚拟键消息转换为字符消息,字符消息被寄送到当前线程的消息队列里。
		DispatchMessage(&msg);  //函数分派一个消息给窗口过程(回调函数),通常该消息从 GetMessage 函数获得。Windows 的控制权在该函数交给了应用程序。
	}
	return msg.wParam;
}



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

{
	static int    cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth;
	static        int           iDeltaPerLine, iAccumDelta;         // 鼠标滚轮逻辑
	HDC         hdc;
	int         i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd;
	PAINTSTRUCT           ps;
	SCROLLINFO            si;
	TCHAR                         szBuffer[10];
	TEXTMETRIC            tm;
	ULONG                         ulScrollLines;       // 鼠标滚轮逻辑
	switch (message)
	{
	case   WM_CREATE:
		hdc = GetDC(hwnd);
		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
		ReleaseDC(hwnd, hdc);

		//保存三列的宽度
		iMaxWidth = 40 * cxChar + 22 * cxCaps;
		// 鼠标滚轮信息
	case   WM_SETTINGCHANGE:
		SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
		// ulScrollLines通常等于3或0(用于不滚动)
		//车轮δ等于120,所以理想直径为40
		if (ulScrollLines)
			iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
		else
			iDeltaPerLine = 0;
		return 0;
	case   WM_SIZE:
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);
		// 设置垂直滚动条范围和页面大小
		si.cbSize = sizeof(si);
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = NUMLINES - 1;
		si.nPage = cyClient / cyChar;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
		// 设置水平滚动条范围和页面大小
		si.cbSize = sizeof(si);
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = 2 + iMaxWidth / cxChar;
		si.nPage = cxClient / cxChar;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

		return 0;
	case WM_VSCROLL:
		// 获取所有垂直滚动条信息
		si.cbSize = sizeof(si);
		si.fMask = SIF_ALL;
		GetScrollInfo(hwnd, SB_VERT, &si);
		// 保存位置以便以后比较
		iVertPos = si.nPos;
		switch (LOWORD(wParam))
		{
		case   SB_TOP:
			si.nPos = si.nMin;
			break;
		case   SB_BOTTOM:
			si.nPos = si.nMax;
			break;
		case SB_LINEUP:
			si.nPos -= 1;
			break;
		case   SB_LINEDOWN:
			si.nPos += 1;
			break;
		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;
		case   SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;
		case   SB_THUMBTRACK:
			si.nPos = si.nTrackPos;
			break;
		default:
			break;

		}
		// 设置位置,然后检索它。由于调整
		//  在Windows下,它可能与设置的值不同。
		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
		GetScrollInfo(hwnd, SB_VERT, &si);
		// 如果位置已更改,请滚动窗口并进行更新
		if (si.nPos != iVertPos)
		{
			ScrollWindow(hwnd, 0, cyChar * (iVertPos - si.nPos),
				NULL, NULL);
			UpdateWindow(hwnd);
		}
		return 0;
	case   WM_HSCROLL:
		// 获取所有垂直滚动条信息
		si.cbSize = sizeof(si);
		si.fMask = SIF_ALL;
		// 保存位置以供以后进行比较
		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;
		switch (LOWORD(wParam))
		{
		case   SB_LINELEFT:
			si.nPos -= 1;
			break;
		case   SB_LINERIGHT:
			si.nPos += 1;
			break;
		case   SB_PAGELEFT:
			si.nPos -= si.nPage;
			break;
		case   SB_PAGERIGHT:
			si.nPos += si.nPage;
			break;
		case   SB_THUMBPOSITION:
			si.nPos = si.nTrackPos;
			break;
		default:
			break;
		}
		// 设置位置,然后检索它。由于调整
		//   在Windows下,它可能与设置的值不同。
		si.fMask = SIF_POS;
		SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
		GetScrollInfo(hwnd, SB_HORZ, &si);
		// 如果位置已更改,滚动窗口
		if (si.nPos != iHorzPos)
		{
			ScrollWindow(hwnd, cxChar * (iHorzPos - si.nPos), 0,
				NULL, NULL);
		}
		return 0;
	case   WM_KEYDOWN:
		switch (wParam)
		{
		case   VK_HOME:
			SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);
			break;
		case   VK_END:
			SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
			break;
		case   VK_PRIOR:
			SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
			break;
		case   VK_NEXT:
			SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
			break;
		case   VK_UP:
			SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
			break;
		case   VK_DOWN:
			SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
			break;
		case   VK_LEFT:
			SendMessage(hwnd, WM_HSCROLL, SB_PAGEUP, 0);
			break;
		case   VK_RIGHT:
			SendMessage(hwnd, WM_HSCROLL, SB_PAGEDOWN, 0);
			break;
		}
		return 0;
	case   WM_MOUSEWHEEL:
		if (iDeltaPerLine == 0)
			break;
		iAccumDelta += (short)HIWORD(wParam);     // 120 or -120
		while (iAccumDelta >= iDeltaPerLine)
		{
			SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
			iAccumDelta -= iDeltaPerLine;
		}
		while (iAccumDelta <= -iDeltaPerLine)
		{
			SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
			iAccumDelta += iDeltaPerLine;
		}
		return 0;
	case   WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		// 获取垂直滚动条位置
		si.cbSize = sizeof(si);
		si.fMask = SIF_POS;
		GetScrollInfo(hwnd, SB_VERT, &si);
		iVertPos = si.nPos;
		// 获取水平滚动条位置
		GetScrollInfo(hwnd, SB_HORZ, &si);
		iHorzPos = si.nPos;
		// 寻找绘画极限
		iPaintBeg = max(0, iVertPos + ps.rcPaint.top / cyChar);
		iPaintEnd = min(NUMLINES - 1,iVertPos + ps.rcPaint.bottom / cyChar);
		for (i = iPaintBeg; i <= iPaintEnd; i++)
		{
			x = cxChar * (1 - iHorzPos);
			y = cyChar * (i - iVertPos);
			TextOut(hdc, x, y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));
			TextOut(hdc, x + 22 * cxCaps, y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
			SetTextAlign(hdc, TA_RIGHT | TA_TOP);
			TextOut(hdc, x + 22 * cxCaps + 40 * cxChar, y, szBuffer,wsprintf(szBuffer, TEXT("%5d"),GetSystemMetrics(sysmetrics[i].Index)));
			SetTextAlign(hdc, TA_LEFT | TA_TOP);
		}
		EndPaint(hwnd, &ps);
		return 0;
	case   WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值