Here is the essential parts of the code I use to allow scrolling in a self painted Window. If you want an easier life then you can use one of the standard Windows controls (e.g.
Edit Control (Windows Controls) - Win32 apps | Microsoft Learn[
^] ) which does all the work for you.
This handler can be called for both Vertical and Horizontal scroll messages
void OnScrollMsg(
HWND hWnd,
WPARAM wParam,
int sbType
)
{
UINT uCode = LOWORD(wParam);
int nPosition = HIWORD(wParam); SCROLLINFO scrollInfo;
int nOldPos;
ZeroMemory(&scrollInfo, sizeof scrollInfo);
scrollInfo.cbSize = sizeof scrollInfo;
scrollInfo.fMask = SIF_ALL;
if (::GetScrollInfo(hWnd, sbType, &scrollInfo) == 0)
scrollInfo.nPos = -1; nOldPos = scrollInfo.nPos;
switch (uCode)
{
case SB_LINEUP: scrollInfo.nPos -= nPosition == 0 ? 1 : nPosition;
break;
case SB_LINEDOWN: scrollInfo.nPos += nPosition == 0 ? 1 : nPosition;
break;
case SB_PAGEUP: scrollInfo.nPos -= scrollInfo.nPage;
break;
case SB_PAGEDOWN: scrollInfo.nPos += scrollInfo.nPage;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
scrollInfo.nPos = nPosition;
break;
case SB_TOP: scrollInfo.nPos = 0;
break;
case SB_BOTTOM: scrollInfo.nPos = scrollInfo.nMax + 1;
break;
default:
break;
}
if (scrollInfo.nPos < 0)
scrollInfo.nPos = 0;
if (scrollInfo.nPos >= scrollInfo.nMax - (int)scrollInfo.nPage)
scrollInfo.nPos = scrollInfo.nMax - scrollInfo.nPage;
if (nOldPos != scrollInfo.nPos)
{
::SetScrollInfo(hWnd, sbType, &scrollInfo, TRUE);
::InvalidateRect(hWnd, nullptr, TRUE);
}
}
This function should be called from the
WM_PAINT
handler,
to adjust the settings according to the size of the display Window
as described in the section below this.
int SetScrollRange(
HWND hWnd,
int nBar,
int nPageSize,
int nMaxRange
)
{
SCROLLINFO scrollInfo;
ZeroMemory(&scrollInfo, sizeof scrollInfo);
scrollInfo.cbSize = sizeof scrollInfo;
scrollInfo.fMask = SIF_ALL;
::GetScrollInfo(hWnd, nBar, &scrollInfo);
scrollInfo.nPage = nPageSize; scrollInfo.nMax = nMaxRange; ::SetScrollInfo(hWnd, nBar, &scrollInfo, TRUE);
return scrollInfo.nPos;
}
In your
WM_PAINT
handler before you start paining the window you need to adjust the start points based on the scroll ranges. You need to make
these calls once you have made any adjustments to the size of your
display window.
int viewHeight = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
int nLine = SetScrollRange(hWnd, SB_VERT, viewHeight / static_cast<int>(charHeight), pVpstr->size());
int viewWidth = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
int nChar = SetScrollRange(hWnd, SB_HORZ, viewWidth / static_cast<int>(charWidth), maxWidth);
You then use
nLine
and
nChar
to set the starting points for displaying the data. When I say "starting" points, I mean the first line or character of your data. You still paint into
the full viewport of your Window. So the first line displays at Y-offset 0, and the first character at
X-offset 0.
I hope that makes sense.