首先是测试的代码
#include <windows.h>
#pragma comment(lib, "winmm")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("HelloWin");
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 = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, // window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
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)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
static int cnt=0;
static int PaintBegin;
static int PaintEnd;
static TCHAR* szTest[] = { TEXT("11111111111111111111"),
TEXT("22222222222222222222"),
TEXT("33333333333333333333"),
TEXT("44444444444444444444"),
TEXT("55555555555555555555") };
static RECT rectTest;
static TCHAR szBuffer[128];
rectTest.top = 0; rectTest.left = 0;
rectTest.right = 160; rectTest.bottom = 100;
switch (message)
{
case WM_CREATE:
PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_UP:
case VK_DOWN:
cnt++;
ScrollWindow(hwnd, 0, -20, &rectTest, &rectTest);
break;
default:
break;
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//一
/*
for (int i = 0; i < 5; i++)
{
TextOut(hdc, 0, i * 20, szTest[i], 20);
}
*/
//二
/*
if (cnt == 0)
{
for (int i = 0; i < 5; i++)
{
TextOut(hdc, 0, i * 20, szTest[i], 20);
}
}
else
{
TextOut(hdc, 0, 4 * 20, szTest[cnt], 20);
}
*/
//三
PaintBegin = max(0, cnt+ps.rcPaint.top/20);
PaintEnd = (cnt == 0 ? 4 : (cnt + ps.rcPaint.bottom/20));
GetClientRect(hwnd, &rect);
for (int i = PaintBegin; i <= PaintEnd; i++)
{
TextOut(hdc, 0, (i - cnt) * 20, szTest[i%5], 20);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
这个测试是对左上角的1小块区域进行滚动测试
经过代码一的测试,ScrollWindow函数确实只是单纯的将指定区域内的内容滚动,滚动后下面留下的区域成为无效区。所以WM_PAINT消息应该针对这个留下来的无效去进行绘制,即使WM_PAINT消息对整个大的区域进行了绘制也只有下面的一小块无效区的才能显示出来
经过代码二的测试,WM_PAINT消息针对无效区绘制是可行的,代码二可实现一部分的循环滚动即将移到上面的移动到下面只不过,当cnt变大时,越界了,同时WM_PAINT里有两套逻辑,代码二也仅仅针对了向下拖动了一行,两行,三行,……的情况
代码三的代码与前面编过的滚动条实验的代码类似,只不过由于是循环滚动,我可以视要输出的数组长度为无限,所以PaintEnd里面没有进行min,同时由于之前的滚动条的代码是针对整个客户区的,而这次循环滚动的代码一开始WM_PAINT是针对整个客户去的,但是滚动中是针对一小部分区域的,所以要进行一个判断,似乎这个判断逃避不了(应该是) 同时这个代码针对连续的移动也是可行的(应该是)