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