我有一个带有两个滚动条的窗口,当调整窗口大小时,滚动条会重新定位。在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;
}
答案 0 :(得分:3)
您可以在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
中完成所有背景画。您仍然需要InvalidateRect
WM_SIZE
编辑---------------------------------
调整窗口大小时,会调用WM_ERASEBKGND
来更新背景。接下来会调用WM_PAINT
,但屏幕上不会显示所有WM_PAINT
更改。 Windows认为控件边缘旁边只有一条细线需要更新,因此只重画屏幕的那个区域。
如@xMRI所述,您应该设置wc.style = CS_HREDRAW | CS_VREDRAW
。这与在InvalidateRect(hWnd, 0, FALSE)
中调用WM_SIZE
相同。
有时您需要InvalidateRect(hWnd, 0, TRUE)
强制删除所有背景,但上面的示例不需要完全背景擦除。您还可以尝试使用WS_CLIPCHILDREN
标志来减少闪烁和奇怪的重绘。