我有一个带有两个滚动条的窗口,滚动条会在调整窗口大小时重新定位。在 WM_PAINT
处理程序中,我在滚动条之前绘制了一个填充的白色矩形:
现在,我假设在调整窗口大小时会发生以下情况:
- 首先,发送一条
WM_SIZE
消息。在它的处理程序中,我重新定位了 滚动条。 - 其次,发送一个
WM_PAINT
消息。在它的处理程序中我重绘 填充的白色矩形。
但是当我垂直调整窗口大小时,会发生以下情况:
当我水平调整窗口大小时,会发生以下情况:
这是我的代码:
#include <Windows.h>
HWND hHorizontalScrollbar;
HWND hVerticalScrollbar;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Get width and height of client area for hWnd
RECT rect;
GetClientRect(hWnd, &rect);
// Draw a filled white rectangle just before the scrollbars
Rectangle(hdc, rect.left, rect.top, rect.right - 17, rect.bottom - 17);
EndPaint(hWnd, &ps);
}
break;
case WM_SIZE:
{
// Get width and height of client area for hWnd
RECT rect;
GetClientRect(hWnd, &rect);
// Change y and width of horizontal scrollbar
MoveWindow(hHorizontalScrollbar, 0, rect.bottom - 17, rect.right - 220, 17, TRUE);
// Change x and height of vertical scrollbar
MoveWindow(hVerticalScrollbar, rect.right - 17, 0, 17, rect.bottom - 220, TRUE);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(0, "WinClass", "", WS_OVERLAPPEDWINDOW, 600, 300, 400, 400, NULL, NULL, hInstance, NULL);
// Create horizontal Scrollbar
hHorizontalScrollbar = CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE| SBS_HORZ, 0, 333, 300, 17, hWnd, NULL, hInstance, NULL);
// Create vertical Scrollbar
hVerticalScrollbar = CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE| SBS_VERT, 333, 0, 17, 300, hWnd, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
最佳答案
您可以添加 InvalidateRect
以在 WM_SIZE
中重绘:
case WM_SIZE:
RECT rect;
GetClientRect(hWnd, &rect);
MoveWindow(hHorizontalScrollbar, 0, rect.bottom - 17, rect.right - 220, 17, TRUE);
MoveWindow(hVerticalScrollbar, rect.right - 17, 0, 17, rect.bottom - 220, TRUE);
InvalidateRect(hWnd, 0, TRUE); //*** add this
此外,要添加滚动条,您可能不需要创建控件,只需添加 WS_VSCROLL
和 WS_HSCROLL
标志即可:
HWND hWnd = CreateWindowEx(0, "WinClass", "", WS_VSCROLL|WS_HSCROLL|WS_OVERLAPPEDWINDOW, 600, 300, 400, 400, NULL, NULL, hInstance, NULL);
请注意,如果在 WM_PAINT
中完成了很多绘画,那么请考虑覆盖 WM_ERASEBKGND
并中断,这样它就不会做任何事情。在 WM_PAINT
中完成所有背景绘制。您仍然需要 WM_SIZE
InvalidateRect
编辑--------------------------------
当您调整窗口大小时,WM_ERASEBKGND
被调用以更新背景。接下来调用 WM_PAINT
,但并非所有 WM_PAINT
更改都显示在屏幕上。 Windows 认为控件边缘旁边只有一条细线需要更新,因此只重绘屏幕的那个区域。
如@xMRI 所述,您应该设置 wc.style = CS_HREDRAW | CS_VREDRAW
。这与在 WM_SIZE
中调用 InvalidateRect(hWnd, 0, FALSE)
相同。
有时您需要 InvalidateRect(hWnd, 0, TRUE)
来强制删除所有背景,但上面的示例不需要完全删除背景。您还可以尝试使用 WS_CLIPCHILDREN
标志来减少闪烁和奇怪的重绘。
关于c - 使用滚动条调整窗口大小时出现奇怪的效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32835771/