Reputation:
I have a window with two scrollbars, the scrollbars are repositioned when the window is resized. Inside the WM_PAINT
handler, I draw a filled white rectangle just before the scrollbars:
Now, what I assumed will happen when I resize the window is the following:
WM_SIZE
message is sent. Inside its handler I reposition the
scrollbars.WM_PAINT
message is sent. Inside its handler I redraw
the filled white rectangle.But when I resize the window vertically, this is what happens:
And when I resize the window horizontally, this is what happens:
This is my code:
#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;
}
Upvotes: 0
Views: 998
Reputation: 31599
You can add InvalidateRect
to repaint in 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
Also, to add scroller, you may not need to create controls, you can just add WS_VSCROLL
and WS_HSCROLL
flag:
HWND hWnd = CreateWindowEx(0, "WinClass", "", WS_VSCROLL|WS_HSCROLL|WS_OVERLAPPEDWINDOW, 600, 300, 400, 400, NULL, NULL, hInstance, NULL);
Note, if there is a lot of painting done in WM_PAINT
then consider overriding WM_ERASEBKGND
and break so it doesn't do anything. Do all the background painting in WM_PAINT
. You still need InvalidateRect
in WM_SIZE
Edit ---------------------------------
When you resize the window, WM_ERASEBKGND
is called to update the background. WM_PAINT
is called next, however not all WM_PAINT
changes are shown on the screen. Windows thinks that there is only a thin line next to the control's edge which needs updating so only that area of the screen is repainted.
As noted by @xMRI, you should set wc.style = CS_HREDRAW | CS_VREDRAW
. This would be same as calling InvalidateRect(hWnd, 0, FALSE)
in WM_SIZE
.
Sometimes you need InvalidateRect(hWnd, 0, TRUE)
to force erasing all of the background, but the above example doesn't need full background erase. You can also try WS_CLIPCHILDREN
flag to reduce flicker and strange repaint.
Upvotes: 3